---
title: "Replication Material: Why the Core of the AfD’s Support Will Not Shift to the BSW: Explaining the Persistence of Far-Right Support in Thuringia, 2024"
author: " "
date: "`r Sys.Date()`"
output: 
  html_document:
    theme: flatly
    toc: yes
    toc_float:
      collapsed: no
      smooth_scroll: no
    number_sections: no
    code_folding: none # not possible to toggle code visibility
---

```{r setup R, include=FALSE}
#### Load packages and data ####
knitr::opts_chunk$set(echo = TRUE)

rm(list=ls())
setwd("~/Desktop/GerPol_replic")
options(scipen=999)

library(haven)
library(car)
library(questionr)
library(survey)
library(DescTools)
library(psych)
library(wdm)
library(jtools)
library(tidyverse)
library(ggeffects)
library(effects)
library(showtext)
library(cowplot)
library(GGally)

library(knitr)
library(kableExtra)
library(modelsummary)

# data
# load("tm2024.RData")
tm <- read_sav("ZA6345_v9-0-0.sav")
tm <- tm %>% 
  filter(welle == 2024)
head(tm[,30:35])
names(tm)

# Google Fonts
font_add_google(name = "Fira Sans",
                family = "Fira Sans")

myfont<- "Fira Sans"

showtext_auto() 
showtext_opts(dpi = 300)


#### Define functions ####

##### functions for output and model fit svyglm #####
## function for most model fit
# This function will output the following model fit statistics: Nagelkerke Pseudo R2, AIC; 
# note this function is used for models computed with svyglm (and the quasibinomial argument)
model_output <- function(m) {
  list(
    Nagel = round(psrsq(m, "Nagel"),3),
    AIC = round(AIC(m),3)
  )
}

## function for LRT (under svyglm/quasibinomial)
# the function outputs the result of a LRT and a Wald Test on svyglm data
# it first calculates the null model, 
# then compares full model to null model using anova
# inputs: dv = the DV, df = the dataframe, m_full = full model
# Note that you need to input the DV as a string: "my_var"
lrt_fun_svyglm <- function(dv, df_w, m_full) {
  # null model
  null_formula <- as.formula(paste(dv, "~ 1")) # outputs: dv ~ 1
  m_null <- svyglm(null_formula, # is: dv ~ 1
                   family = quasibinomial(link="logit"),
                   design = df_w) 
  list(
    # LRT
    LRT = anova(m_null, m_full),
    # Wald 
    Wald = anova(m_null, m_full, method = "Wald")
  )
}

## formula that computes a deviance-based quasi-McFadden
# it first calculates the null model, then McFaddens
# inputs: dv = the DV, df = the dataframe, m_full = full model
# Note that you need to input the DV as a string: "my_var"
quasi_mcfadden <- function(dv, df_w, m_full) {
  # null model
  null_formula <- as.formula(paste(dv, "~ 1")) # outputs: dv ~ 1
  m_null <- svyglm(null_formula, # is: dv ~ 1
                   family = quasibinomial(link="logit"),
                   design = df_w) 
  # Compute McFadden's 
  dev_full <- deviance(m_full) # deviance full model
  dev_null <- deviance(m_null) # based on null model
  mcfadden <- 1 - (dev_full / dev_null) # quasi Mc Fadden 
  return(round(mcfadden,3))
}


##### functions for output and model fit glm, unweighted #####
# We use our main model, but this time no (!) weights are employed

## function for summary model output for unweighted data / glm models
# This function will output: 
# the odds ratio, a conf.int, the number of observations, 
# as well as model fit statistics: Nagelkerke R2, McFadden R2, AIC, LogLik
model_output_unweighted <- function(m) {
  list(
    # Model output
    OR = round(odds.ratio(m),3),
    CI = round(confint(m),3),
    # Model fit
    R2 = round(PseudoR2(m, c("Nagel", "McFadden")),3),
    AIC = round(AIC(m),3),
    LogLik = round(logLik(m),3),
    Obs = length(m$fitted.values)
  )
}

## function for LRT
# the function outputs the result of a likelihood ratio test. 
# it first calculates the null model, and then compares full model to null model using anova
# inputs: dv = the DV, df = the dataframe, m_full = full model
lrt_fun_binomial <- function(dv, df, m_full) {
  # null model
  null_formula <- as.formula(paste(dv, "~ 1")) # outputs: dv ~ 1
  m_null <- glm(null_formula, # is: dv ~ 1
                family = binomial(link="logit"),
                data=df)
  # LRT
  return(anova(m_null, m_full))
}


##### function for predicted probabilities plot #####
## function to create predicted probability plots
# we need to input: 
# m = model, my_term = the coefficient from the model, my_color = line and CI color in plot
pred_probs_plt_fun <- function(m, my_term, my_color) {
  # compute probabilities
  probabilities <- ggeffect(m, terms = paste(my_term)) # terms = coefficient(s)
  probabilities <- as_tibble(probabilities) # make tibble so ggplot can read it
  # predicted probabilities plot
  p <- probabilities %>% 
    ggplot(aes(x = x, y = predicted)) + 
    geom_line(color=paste(my_color)) +
    geom_ribbon(aes(ymin = conf.low, ymax = conf.high), alpha = 0.2, fill=paste(my_color)) + # add CI (as shade)
    theme_minimal()+
    theme(text = element_text(myfont, size = 10, color = "black"), # text and label size
          axis.text = element_text(size = 6, color = "black"))
  return(p)
}

```

```{r coef names models, echo=F}
#### Set coefficient names for regression output ####
coef_names = c("REX" = "Far-right attitudes", "Ethno" = "Ethnocentrism", "NSIdeo" = "Neo-Nazi ideology",
               "alter" = "Age", "genderfemale" = "Gender (female)", "edu_grno Abitur" = "Education (no High school diploma)", "fin_sitbad" = "Indiv. financial situation (bad)", "unemployedyes" = "Unemployment", "manual_workeryes" = "Manual worker", "fair_shareno" = "Econ. deprivation",
               "anti_immigration" = "Anti-immigrant attitudes", "anti_feminismagree" = "Anti-feminism", "anti_transagree" = "Anti-trans attitudes",
               "swd_grdissatisfied" = "Dissatisf. with democracy", "pol_distrust" = "Distrust", "RR" = "Place-based resentment", "second_classagree" = "Second class (yes)", "gdrnostalgia" = "GDR nostalgia",
               "status_anxyes" = "Status anxiety", "econ_situation_thbad" = "Economic situation Thuringia (bad)",
               "lr" = "Left-right self-placement (right)", "dissat_partiesagree" = "Anti-party sentiment", "ext_efficlow" = "External efficacy (low)", "responsiveagree" = "Responsiveness", "dev_community" = "Development of community"
               )
```



# Data Cleaning and Manipulation

#### Remove respondents non-eligible to vote

```{r remove respondents non-eligible to vote}
# b/c they are actually not in our sampling frame
table(tm$recall_ltw, useNA = "ifany") # 13 = non-eligible to vote
tm <- tm %>%
  filter(is.na(recall_ltw) | recall_ltw != 13)
table(tm$recall_ltw, useNA = "ifany") # check
```

#### DVs: Recall question

Our dependent variable is based on the vote recall question. From this, we create two dummy variables: one indicating whether a respondent voted for the AfD, and one for those who voted for BSW (Bündnis Sahra Wagenknecht).

* `recall_ltw` Which party did you vote for in the state election or did you not vote in the election?
  * 1 – The Left (Die Linke)  
  * 2 – AfD (Alternative for Germany)  
  * 3 – CDU (Christian Democratic Union)  
  * 4 – SPD (Social Democratic Party)  
  * 5 – Greens  
  * 6 – FDP (Free Democratic Party)  
  * 7 – BSW / Bündnis Sahra Wagenknecht  
  * 10 – Other Party  
  * 11 – Did not vote  
  * 12 – Cast invalid vote  
  * 13 – Not eligible to vote  
  * 77 – Does not apply  
  * 88 – Don't know  
  * 99 – No answer

```{r data manipulation DV, include=T}
tm <- tm %>% 
  mutate(recall_ltw_named = case_when(recall_ltw==1 ~"Left",
                                      recall_ltw==2 ~"AfD",
                                      recall_ltw==3 ~"CDU",
                                      recall_ltw==4 ~"SPD",
                                      recall_ltw==5 ~"Greens",
                                      recall_ltw==6 ~"FDP",
                                      recall_ltw==7 ~"BSW",
                                      recall_ltw==10 ~"Other",
                                      recall_ltw==11 ~"non-voter",
                                      recall_ltw==12 ~NA),
         afd = ifelse(recall_ltw_named=="AfD",1,0),
         bsw = ifelse(recall_ltw_named=="BSW",1,0),
         across(c(afd, bsw),
                ~factor(.x,
                      levels = c(0,1),
                      labels = c("no","yes"))),
         recall_voters_only = replace(recall_ltw_named, recall_ltw_named=="non-voter",NA) # voters only to check representativness of sample vs. election result
  )

```

##### Check share of voters by party (representativeness of sample according to election results)

First, let's take a look at the number of AfD and BSW voters in our sample:
```{r explore distribution DV}
table(tm$recall_ltw_named)
```

To check the representativeness of our sample in terms of vote choice, we exclude non-voters and look at the voters in our dataset only. 

```{r share of voters by party}
# unweighted share - without the non-voters
round(prop.table(table(tm$recall_voters_only))*100,1)

# weighted share
tm_w <- svydesign(id=~0, weights=~persgew, data = tm)
absolute <- svytable(~recall_voters_only, tm_w)
round(prop.table(absolute)*100,1)
```
BSW voters are well represented in our data, making up 13.7% (unweighted) / 13.6% (weighted) of respondents, compared to their actual election result of 15.8%.
While AfD voters are numerous in our data, they are underrepresented: they account for only 15.5% / 21.7% in the data, whereas their actual vote share was 32.8%.


#### IVs and Controls

The following independent variables and controls were introduced, if not indicated otherwise, items were rated on a 4-pint scale (1=fully disagree, 4=fully agree)

* `anti_immigration`is a mean index with one missing allowed consisting of the following items:
  * `V12A` Foreigners only come to Germany to abuse the welfare state.
  * `V12B` Germany is dominated by foreigners to a dangerous degree.
  * `V12MU` Muslims should be banned from immigrating to Germany.
  * `V469` Cultural differences prevent most refugees and asylum seekers from successfully integrating into Germany.
  * `V356C` Immigrants living in Germany should be allowed to maintain their lifestyle, even if it differs from that of Germans. (reverse)
* `anti-feminism` was operationalized creating a dummy variable from the item `V12KAF` Feminism systematically disadvantages men in our society.
* `anti-trans` was operationalized creating a dummy variable from the item `V12TS` It is okay for people to undergo gender changes, for example, through surgeries and hormone treatments. (reverse coded)
* Far-right attitudes `REX` are coded based on 10 items that form two subscales - each subscale is a mean index with one missing allowed
  * Ethnocentrism `Ethno`
   * `V12A` Foreigners only come to Germany to abuse the welfare state.
   * `V12B` Germany is dominated by foreigners to a dangerous degree. 
   * `V12C` What we need in our country is to forcefully and aggressively assert German interests toward foreign countries.
   * `V12E` Other countries don’t match Germany’s achievements.
  * Neo-Nazi ideology `NSIdeo`
   * `V12D` For the national interest, a dictatorship is under certain conditions the best form of government.
   * `V12F` Foreigners ought to marry only among themselves.
   * `V12G` There is worthy and unworthy life.
   * `V12H` National Socialism had its positive aspects.
   * `V12I` The Jews are just peculiar and don’t really fit in with us.
   * `V12J` As in nature, in society the fittest should win.
* `swd_gr` Dissatisfaction with democracy was operationalized creating a dummy variable from the item `V07` How satisfied or dissatisfied are you with democracy as it functions in practice in Germany? (1=very dissatisfied, 4=very satisfied, reverse coded)
* `pol_distrust` Political distrust is a mean scale with one missing allowed, consisting of 3 items that were each measured on a 5-point response scale: I now read to you a number of public facilities. Please tell me for each one whether you trust it fully, largely trust it, partially trust it, rather not trust it, or not trust it at all. The scale was reversed, so that higher values measure distrust.´
  * `V09A` How is that with the federal government?
  * `V09B` How is that with the regional government?
  * `V09BT` How is that with the federal parliament (German Bundestag)?
* Place-based resentment `RR` is a mean scale with one missing allowed, consisting of three items - one for the economic, political, and cultural dimension of the concept
  * `RR1B` Politicians in Berlin have done too little to improve the economic situation in my region. (economic)
  * `RR2B` People in the rest of Germany don't understand or respect how people in my region live. (cultural)
  * `RR4B` Politicians in Berlin do not care about the region where I live. (political)
* `gdr` GDR nostalgia was operationalized creating a dummy variable from the item `V10` The GDR had more good than bad sides.
* `second_class` was created as a dummy variable from the item `V18` West Germans treat East Germans as second-class citizens.
* `fin_sit` was created as a dummy variable from the item `V02` When you think about your own financial situation, would you say it is very good, good, somewhat poor, or bad?
* `fair_share` was created as a dummy variable from the item `V131` I worry that, due to societal developments, I will end up on the losing side of life.
* `status_anx` was created as a dummy variable from the item `V12L` Compared to how others in Germany live, do you think you personally receive your fair share, more than your fair share, slightly less, or much less?
* `econ_situation_th` was created as a dummy variable from the item `V01` What is your general assessment of the current economic situation in Thuringia?

* Additional controls include age (`alter`), gender (`gender`), education (`edu_gr`), occupation (`unempolyed`, `manual_worker`)


```{r data manipulation IVs, include=T}
# cultural conservatism

# reverse
tm <- tm %>% 
  mutate(
    V12N_rev = 5-V12N,
    V356C_rev = 5-V356C,
    V12TS_rev = 5-V12TS # anti-trans
  )

# check NAs
colSums(is.na(tm[,c("V12A", "V12B", "V12N_rev", "V12MU", "V469", "V356C_rev")]))
# => We have many NAs for V12N (336) => let's not use that item in the mean index then


# recodes
tm <- tm %>% 
  mutate(anti_immigration = ifelse(
    (is.na(V12A) + is.na(V12B) + is.na(V12MU) + is.na(V469) + is.na(V356C_rev)) > 1, NA,
                            rowMeans(across(
                              c(V12A, V12B, V12MU, V469, V356C_rev)), na.rm=T)),
         V12KAF = replace(V12KAF, V12KAF>87, NA),
         anti_feminism = ifelse(V12KAF>2,1,0), # agree=anti-feminist
         anti_trans = ifelse(V12TS_rev>2,1,0), # agree=anti-trans
         across(c(anti_feminism, anti_trans),
           ~factor(.x,
                   levels = c(0,1),
                   labels = c("disagree", "agree")))
           )


# Far-right attitudes 
# We code 3 mean scales: Far-right attitudes, Ethnocentrism (1 missing allowed), Neo-Nazi ideology (1 missing allowed)
# Far-right attitudes scale = based on the 2 prev. mean scales
# Dummies for the crosstabs

tm <-tm %>% 
  mutate(Ethno = ifelse((is.na(V12A) + is.na(V12B) + is.na(V12C) + is.na(V12E)) > 1, NA, 
                         rowMeans(across(
                           c(V12A, V12B, V12C, V12E)), na.rm=T)),
         NSIdeo = ifelse((is.na(V12D) + is.na(V12F) + is.na(V12G) + is.na(V12H) + is.na(V12I) + is.na(V12J)) > 1, NA,
                          rowMeans(across(
                            c(V12D, V12F, V12G, V12H, V12I, V12J)), na.rm=T)),
         REX = (Ethno+NSIdeo)/2, # REX mean index
         REXgr = ifelse(REX>2.5,1,0), # REX Dummy
         REXgr = factor(REXgr,
                        levels = c(0,1),
                        labels = c("not far-right", "far-right")),
         Ethnogr = ifelse(Ethno>2.5,1,0), # Ethno Dummy
         Ethnogr = factor(Ethnogr,
                          levels = c(0,1),
                          labels = c("no etnocentrism", "ethnocentrism")),
         NSIdeogr = ifelse(NSIdeo>2.5,1,0), # NS-Ideo Dummy
         NSIdeogr = factor(NSIdeogr,
                           levels = c(0,1),
                           labels = c("no neo-Nazi ideology", "neo-Nazi ideology"))
  ) 


# political grievances
## alternative operationalizations dissatisfaction politics
# reverse
tm$v699_rev <- 5-tm$V699

# recodes
tm <- tm %>% 
  mutate(second_class = ifelse(V18>2,1,0),
         second_class = factor(second_class,
                               levels = c(0,1),
                               labels = c("disagree", "agree")),
         gdr = ifelse(V10>2,1,0),
         gdr = factor(gdr,
                      levels = c(0,1),
                      labels = c("no nostalgia", "nostalgia")),
         V07 = replace(V07, tm$V07>87, NA),
         swd_gr = ifelse(V07>2,1,0),
         swd_gr = factor(swd_gr,
                         levels = c(0,1),
                         labels = c("dissatisfied", "satisfied")),
         swd_gr = relevel(swd_gr, ref = "satisfied"),
         pol_trust = ifelse((is.na(V09A) + is.na(V09B) + is.na(V09BT)) > 1, NA,
                            rowMeans(across(
                              c(V09A, V09B, V09BT)), na.rm=T)),
         pol_distrust = 6-pol_trust, # reverse it, so we get distrust as high values
         dissat_parties = ifelse(V17>2,1,0),
         dissat_parties = factor(dissat_parties,
                                 levels=c(0,1),
                                 labels = c("disagree", "agree")),
         dissat_parties = relevel(dissat_parties,ref="disagree"), # reference category agree = dissatisfaction 
         ext_effic = ifelse(V139J>2,1,0),
         ext_effic = factor(ext_effic,,
                            levels=c(0,1),
                            labels = c("high", "low")),
         ext_effic = relevel(ext_effic,ref="high"), # reference category
         responsive = ifelse(v699_rev>2,1,0), # Die Politiker bemühen sich NICHT darum...
         responsive = factor(responsive,
                             levels=c(0,1),
                             labels = c("disagree", "agree")),
         responsive = relevel(responsive,ref="disagree"), # agree=low responsiveness
         RR = ifelse((is.na(RR1B) + is.na(RR2B) + is.na(RR4B)) > 1, NA,
                     rowMeans(across(
                       c(RR1B, RR2B, RR4B)), na.rm=T)),
         dev_community = as.numeric(SL_VER),
         dev_community = 6-dev_community # reversing it would be in line with the place-based resentment argument
  )


# Socio-demographics and other controls
tm <- tm %>% 
  mutate(gender = case_when(sex==1~0, # => make "divers" = NA
                            sex==2~1,
                            sex==3 |
                              sex==4~NA),
         gender = factor(gender,
                         levels = c(0,1),
                         labels = c("male", "female")),
         edu_gr = ifelse(bildung_neu>4,1,0),
         edu_gr = factor(edu_gr,
                         levels = c(0,1),
                         labels = c("no Abitur", "Abitur or higher")),
         edu_gr = relevel(edu_gr, ref = "Abitur or higher"), # reference category
         alter = as.numeric(alter),
         fin_sit = ifelse(V02>2,1,0),
         fin_sit = factor(fin_sit,
                          levels = c(0,1),
                          labels = c("bad", "good")),
         fin_sit = relevel(fin_sit, ref="good"), # reference category
         fair_share = ifelse(V131>2,1,0),
         V12L = replace(V12L, V12L>87, NA),
         status_anx = ifelse(V12L>2,1,0),
         unemployed = ifelse(berufttg==5,1,0), # 5 = unemployed
         beruf_new = ifelse(is.na(beruf), 99, as.numeric(beruf)), # make sure to include pensioneers etc. 
         manual_worker = ifelse(beruf_new==1,1,0),
         across(c(fair_share, status_anx, unemployed, manual_worker),
                ~factor(.x,
                        levels = c(0,1),
                        labels = c("no", "yes"))),
         unemployed = relevel(unemployed, ref="no"), # reference category
         fair_share = relevel(fair_share, ref="yes"), # reference category
         manual_worker = relevel(manual_worker, ref="no"), # reference category
         V01 = replace(V01, tm$V01>87, NA),
         econ_situation_th = ifelse(V01>2,1,0),
         econ_situation_th = factor(econ_situation_th,
                                        levels = c(0,1),
                                        labels = c("bad", "good")),
         econ_situation_th = relevel(econ_situation_th, ref = "good"), # reference category
         lr = as.numeric(V19), # 7 = far-right
  )


# store all in tm_all as backup to select diff variables in diff model specifications
tm_all <- tm # store one df with all

```


# Bivariate Analysis
```{r set up data bivariate analysis}
## Cultural and political grievances
# Select vars we need
tm <- tm_all %>% 
  select(alter, gender, edu_gr, lr, fin_sit, fair_share, status_anx, anti_immigration, anti_feminism, anti_trans, econ_situation_th, second_class, gdr, swd_gr, pol_distrust, RR, afd, bsw, recall_ltw_named, persgew)

# data w/o NAs
tm <- tm %>% 
  drop_na()

# Surveydesign object
tm_w <- svydesign(id=~1, weights=~persgew, data = tm) 

## Far-right
# select vars we need
tm_rex <- tm_all %>% 
  select(REX, REXgr, Ethno, Ethnogr, NSIdeo, NSIdeogr, persgew, recall_ltw_named, afd, bsw)

# drop NA 
tm_rex <- tm_rex %>% 
  drop_na() 

# surveydesign object
tm_rex_w <- svydesign(id=~1, weights=~persgew, data = tm_rex)
```


#### Bivariate analysis cultural conservatism
```{r bivariate analysis cultural grievances}

# Cultural conservatism
## Anti-immigrant
list(
  # with indep_test from wdm
  afd_wdm=indep_test(as.numeric(tm$afd), tm$anti_immigration,
           weights = tm$persgew,
           method = "pearson"),
  bsw_wdm=indep_test(as.numeric(tm$bsw), tm$anti_immigration,
           weights = tm$persgew,
           method = "pearson"),
  # for robustness reasons, let's use the more conservative svycor (jtools) as well...
  afd_svycor=svycor(~as.numeric(afd)+anti_immigration, design=tm_w,
       sig.stats=T),
  bsw_svycor=svycor(~as.numeric(bsw)+anti_immigration, design=tm_w,
       sig.stats=T)
)


## Anti feminism
absolute <- svytable(~anti_feminism+recall_ltw_named, tm_w)
percent <- round(prop.table(absolute,2)*100,1)
df <- as.data.frame.matrix(percent)

kable(df, 
      caption = "Column Percentages: Anti-feminist Attitudes by Recall",
      digits = 1) 

## Anti-trans
absolute <- svytable(~anti_trans+recall_ltw_named, tm_w)
percent <- round(prop.table(absolute,2)*100,1)
df <- as.data.frame.matrix(percent)

kable(df, 
      caption = "Column Percentages: Anti-trans Attitudes by Recall",
      digits = 1)

```


#### Bivariate analysis political grievances
```{r bivariate analysis political grievances}
## SWD
absolute <- svytable(~swd_gr+recall_ltw_named, tm_w)
percent <- round(prop.table(absolute,2)*100,1)
df <- as.data.frame.matrix(percent)

kable(df, 
      caption = "Column Percentages: Dissatisfaction with Democracy by Recall",
      digits = 1)

## Distrust
list(
  # with indep_test from wdm
  afd_wdm=indep_test(as.numeric(tm$afd), tm$pol_distrust,
           weights = tm$persgew,
           method = "pearson"),
  bsw_wdm=indep_test(as.numeric(tm$bsw), tm$pol_distrust,
           weights = tm$persgew,
           method = "pearson"),
  # for robustness reasons, let's use the more conservative svycor (jtools) as well...
  afd_svycor=svycor(~as.numeric(afd)+pol_distrust, design=tm_w,
       sig.stats=T),
  bsw_svycor=svycor(~as.numeric(bsw)+pol_distrust, design=tm_w,
       sig.stats=T)
)

# Placce-based resentment
list(
  # with indep_test from wdm
  afd_wdm=indep_test(as.numeric(tm$afd), tm$RR,
           weights = tm$persgew,
           method = "pearson"),
  bsw_wdm=indep_test(as.numeric(tm$bsw), tm$RR,
           weights = tm$persgew,
           method = "pearson"),
  # for robustness reasons, let's use the more conservative svycor (jtools) as well...
  afd_svycor=svycor(~as.numeric(afd)+RR, design=tm_w,
       sig.stats=T),
  bsw_svycor=svycor(~as.numeric(bsw)+RR, design=tm_w,
       sig.stats=T)
)

## East German-identity-related grievances
absolute<- svytable(~gdr+recall_ltw_named, tm_w)
percent <- round(prop.table(absolute,2)*100,1)
df <- as.data.frame.matrix(percent)

kable(df, 
      caption = "Column Percentages: GDR nostalgia by Recall",
      digits = 1)

absolute <- svytable(~second_class+recall_ltw_named, tm_w)
percent <- round(prop.table(absolute,2)*100,1)
df <- as.data.frame.matrix(percent)

kable(df, 
      caption = "Column Percentages: Collective deprivation by Recall",
      digits = 1)
```


#### Crosstables far-right attitudes by recall
```{r crosstabs vote choice far-right}
absolute <- svytable(~REXgr+recall_ltw_named, tm_rex_w)
percent <- round(prop.table(absolute,2)*100,1)
df <- as.data.frame.matrix(percent)

kable(df, 
      caption = "Column Percentages: Far-right Attitudes by Recall",
      digits = 1)

absolute <- svytable(~Ethnogr+recall_ltw_named, tm_rex_w)
percent <- round(prop.table(absolute,2)*100,1)
df <- as.data.frame.matrix(percent)

kable(df, 
      caption = "Column Percentages: Ethnocentrism by Recall",
      digits = 1)

absolute <- svytable(~NSIdeogr+recall_ltw_named, tm_rex_w)
percent <- round(prop.table(absolute,2)*100,1)
df <- as.data.frame.matrix(percent)

kable(df, 
      caption = "Column Percentages: Neo-Nazi Ideology by Recall",
      digits = 1)
```


#### Correlations between vote choice and far-right attitudes
```{r correlations vote choice far-right}
# far-right
list(
  # with indep_test from wdm
  afd_wdm=indep_test(as.numeric(tm_rex$afd), tm_rex$REX,
           weights = tm_rex$persgew,
           method = "pearson"),
  bsw_wdm=indep_test(as.numeric(tm_rex$bsw), tm_rex$REX,
           weights = tm_rex$persgew,
           method = "pearson"),
  # for robustness reasons, let's use the more conservative svycor (jtools) as well...
  afd_svycor=svycor(~as.numeric(afd)+REX, design=tm_rex_w,
       sig.stats=T),
  bsw_svycor=svycor(~as.numeric(bsw)+REX, design=tm_rex_w,
       sig.stats=T)
)

# Ethnocentrism
list(
  # with indep_test from wdm
  afd_wdm=indep_test(as.numeric(tm_rex$afd), tm_rex$Ethno,
           weights = tm_rex$persgew,
           method = "pearson"),
  bsw_wdm=indep_test(as.numeric(tm_rex$bsw), tm_rex$Ethno,
           weights = tm_rex$persgew,
           method = "pearson"),
  # for robustness reasons, let's use the more conservative svycor (jtools) as well...
  afd_svycor=svycor(~as.numeric(afd)+Ethno, design=tm_rex_w,
       sig.stats=T),
  bsw_svycor=svycor(~as.numeric(bsw)+Ethno, design=tm_rex_w,
       sig.stats=T)
)

# Neo-Nazi ideology
list(
  # with indep_test from wdm
  afd_wdm=indep_test(as.numeric(tm_rex$afd), tm_rex$NSIdeo,
           weights = tm_rex$persgew,
           method = "pearson"),
  bsw_wdm=indep_test(as.numeric(tm_rex$bsw), tm_rex$NSIdeo,
           weights = tm_rex$persgew,
           method = "pearson"),
  # for robustness reasons, let's use the more conservative svycor (jtools) as well...
  afd_svycor=svycor(~as.numeric(afd)+NSIdeo, design=tm_rex_w,
       sig.stats=T),
  bsw_svycor=svycor(~as.numeric(bsw)+NSIdeo, design=tm_rex_w,
       sig.stats=T)
)

```


# Full Logistic Regression Models Cultural Conservatism and Political Grievances

```{r full models svyglm, echo=T, warning=F, message=F}
# select vars we need
tm <- tm_all %>% 
  select(alter, gender, edu_gr, lr, fin_sit, fair_share, status_anx, anti_immigration, anti_feminism, anti_trans, econ_situation_th, second_class, gdr, swd_gr, pol_distrust, RR, afd, bsw, persgew)

# NAs
colSums(is.na(tm))

# remove data with missings
tm <- tm %>% 
  drop_na()
# dim(tm)

# surveydesign object
tm_w <- svydesign(id=~1, weights=~persgew, data = tm)

# models
# AfD
m_afd <- svyglm(afd~anti_immigration+anti_feminism+anti_trans+second_class+gdr+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+fair_share+status_anx+econ_situation_th,
                family = quasibinomial(link="logit"),
                design = tm_w)

# BSW
m_bsw <- svyglm(bsw~anti_immigration+anti_feminism+anti_trans+second_class+gdr+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+fair_share+status_anx+econ_situation_th,
                family = quasibinomial(link="logit"),
                design = tm_w)

```

```{r modelsummary full models svyglm, warning=F, message=F}
modelsummary(
  list("AfD" = m_afd, "BSW" = m_bsw),
  exponentiate = T, # get OR
  stars = T,
  output = "kableExtra",
  statistic = "conf.int",
  gof_omit = "RMSE|R2|Deviance|F|AIC|BIC|Log.Lik",
  title = "Logistic regression models predicting AfD and BSW vote choice (Odds Ratios)",
  coef_rename = coef_names
)
```

The **AfD** model is consistent with what we find regarding voting for RRPs across Europe: anti-immigrant views are crucial, but diverse political grievances do matter as well.

In detail: for the AfD, anti-immigrant views are significantly and positively associated with vote choice. The other dimensions of cultural conservatism (anti-feminism, anti-trans views) are *not* significantly associated. Almost all political grievances (dissatisfaction with democracy, distrust, place-based resentment) are significantly associated with vote choice for the AfD; associations run in the expected direction. Grievances related to East German identity are *not* significant in the full model. Also, the full model shows little support for the losers of modernization thesis.

For **BSW** almost none of our predictors is significantly correlated with vote choice. All measures of cultural conservatism fail to reach statistical significance. Of the political grievances, dissatisfaction with democracy is associated with BSW support; so is GDR nostalgia. Again, we find little support for the losers of modernization thesis. For example, low education is negatively correlated with voting for BSW.


#### Model Fit Statistics

To view model fit statistics, please set `eval = F`and `echo = F`to `TRUE` in the markdown file. 

```{r model fit statistics full models svyglm, echo = F, eval=F}
## AFD
# AIC & Nagelkerke
model_output(m_afd)
# LRT approximation & Wald test
lrt_fun_svyglm("afd", tm_w, m_afd) 
# McFadden Pseudo R2
quasi_mcfadden("afd", tm_w, m_afd) 
# Multicollinearity
vif(m_afd)>4 
# Note that both R2 are not optimal, the psrsq(m_afd, "Nagel") produces a warning; and the quasi McFadden may substantially underestimate model fit

## BSW
# AIC & Nagelkerke
model_output(m_bsw)
# LRT approximation / Wald Test
lrt_fun_svyglm("bsw", tm_w, m_bsw)
# McFadden Pseudo R2
quasi_mcfadden("bsw", tm_w, m_bsw)
# Multicollinearity
vif(m_bsw)>4 
```

What do the Pseudo-R2 values tell us?
It’s striking how much worse the BSW model performs compared to the AfD model when looking at Pseudo-R2 values: 0.118 vs. 0.5. This could support the idea that foreign policy - particularly views on the Russia-Ukraine conflict - is the most decisive factor for BSW vote (Thomeczek, 2024). At the same time, it's important to note that our dataset doesn’t include variables that adequately capture attitudes on the socio-economic dimension. We will, however, account for left-right self-placement in the robustness checks [See robustness checks](#2-full-svyglm-models-with-left-right-self-placement)



# Far-right Attitudes

## Full Logistic Regression Models Far-right Attitudes
```{r full models far-right}
# select vars we need
tm_rex <- tm_all %>% 
  select(REX, REXgr, Ethno, Ethnogr, NSIdeo, NSIdeogr, alter, gender, edu_gr, unemployed, manual_worker, fin_sit, fair_share, status_anx, anti_immigration, anti_feminism, anti_trans, econ_situation_th, second_class, swd_gr, pol_distrust, RR, afd, bsw, persgew)

# drop NA to have same cases in all models
tm_rex <- tm_rex %>% 
  drop_na()

# surveydesign object
tm_rex_w <- svydesign(id=~1, weights=~persgew, data = tm_rex)

# MODELS
m1_rex_afd <- svyglm(afd~REX+anti_feminism+anti_trans+second_class+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share+status_anx+econ_situation_th,
                     family = quasibinomial(link = "logit"),
                     design = tm_rex_w)

m1_rex_bsw <- svyglm(bsw~REX+anti_feminism+anti_trans+second_class+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share+status_anx+econ_situation_th,
                     family = quasibinomial(link = "logit"),
                     design = tm_rex_w)

m1_ethno_afd <- svyglm(afd~Ethno+anti_feminism+anti_trans+second_class+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share+status_anx+econ_situation_th,
                       family = quasibinomial(link = "logit"),
                       design = tm_rex_w)

m1_ethno_bsw <- svyglm(bsw~Ethno+anti_feminism+anti_trans+second_class+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share+status_anx+econ_situation_th,
                       family = quasibinomial(link = "logit"),
                       design = tm_rex_w)

m1_ns_afd <- svyglm(afd~NSIdeo+anti_feminism+anti_trans+second_class+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share+status_anx+econ_situation_th,
                    family = quasibinomial(link = "logit"),
                    design = tm_rex_w)

m1_ns_bsw <- svyglm(bsw~NSIdeo+anti_feminism+anti_trans+second_class+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share+status_anx+econ_situation_th,
                    family = quasibinomial(link = "logit"),
                    design = tm_rex_w)
```

```{r modelsummary full models far-right, warning=F, message=F}
modelsummary(
  list("Far-right (AfD)" = m1_rex_afd,
       "Ethnocentrism (AfD)" = m1_ethno_afd,
       "Neo-Nazi ideology (AfD)" = m1_ns_afd,
       "Far-right (BSW)" = m1_rex_bsw, 
       "Ethnocentrism (BSW)" = m1_ethno_bsw, 
       "Neo-Nazi ideology (BSW)" = m1_ns_bsw
       ),
  exponentiate = T, # get OR
  stars = T,
  output = "kableExtra",
  statistic = "conf.int",
  gof_omit = "RMSE|R2|Deviance|F|AIC|BIC|Log.Lik",
  title = "Table: Full logistic regression models predicting AfD and BSW vote choice with far-right attitudes (Odds Ratios)",
  coef_rename = coef_names
)
```

What do the results tell us?

The most notable change in the full models in contrast to the bivariate models and models with socio-demographic controls that can be found in the robustness checks (see [section on far-right attitudes models](#8-far-right-attitudes-bivariate-and-socio-demographic-controls-models)) is that **neo-Nazi Ideology is no longer significantly linked to AfD voting**. In contrast, the full far-right attitude scale and Ethnocentrism remain significant. This suggests that the effect of far-right attitudes is primarily driven by **Ethnocentrism**, rather than by neo-Nazi Ideology.

None of the three measures of far-right attitudes is significantly linked to BSW support in the full models.


#### Model Fit Statistics

To view model fit statistics, please set `eval = F`and `echo = F`to `TRUE` in the markdown file. 

```{r model fit full models far-right, eval=F, echo=F}
#### AfD ####
## Far-right attitudes
# Nagelkerke & AIC
model_output(m1_rex_afd)
# LRT approximation / Wald Test
lrt_fun_svyglm("afd", tm_rex_w, m1_rex_afd)
# McFadden Pseudo R2
quasi_mcfadden("afd", tm_rex_w, m1_rex_afd)

## Ethnocentrism
# Nagelkerke & AIC
model_output(m1_ethno_afd) 
# LRT approximation / Wald Test
lrt_fun_svyglm("afd", tm_rex_w, m1_ethno_afd)
# McFadden Pseudo R2
quasi_mcfadden("afd", tm_rex_w, m1_ethno_afd)

## neo-Nazi ideology 
# Nagelkerke & AIC
model_output(m1_ns_afd) 
# LRT approximation / Wald Test
lrt_fun_svyglm("afd", tm_rex_w, m1_ns_afd)
# McFadden Pseudo R2
quasi_mcfadden("afd", tm_rex_w, m1_ns_afd)

#### BSW ####
## Far-right attitudes 
# Nagelkerke & AIC
model_output(m1_rex_bsw) 
# LRT approximation / Wald Test
lrt_fun_svyglm("bsw", tm_rex_w, m1_rex_bsw)
# McFadden Pseudo R2
quasi_mcfadden("bsw", tm_rex_w, m1_rex_bsw)

## Ethnocentrism 
# Nagelkerke & AIC
model_output(m1_ethno_bsw) 
# LRT approximation / Wald Test
lrt_fun_svyglm("bsw", tm_rex_w, m1_ethno_bsw)
# McFadden Pseudo R2
quasi_mcfadden("bsw", tm_rex_w, m1_ethno_bsw)

## neo-Nazi ideology 
# Nagelkerke & AIC
model_output(m1_ns_bsw) 
# LRT approximation / Wald Test
lrt_fun_svyglm("bsw", tm_rex_w, m1_ns_bsw)
# McFadden Pseudo R2
quasi_mcfadden("bsw", tm_rex_w, m1_ns_bsw)
```


#### Predicted Probabilities Full Models Far-right Attitudes
```{r pred probs plts full far-right models, echo=F, warning=F, message=F}

# REX plot AfD
p1 <- pred_probs_plt_fun(m1_rex_afd, "REX", "black")
p1 <- p1 +
  labs(x = "Far-right attitudes (1 = low, 4 = high)", 
       y = "Predicted probability")+
  ylim(0,0.93)

# Ethno plot AfD
p2 <- pred_probs_plt_fun(m1_ethno_afd, "Ethno", "steelblue1")
p2 <- p2 +
  labs(x = "Ethnocentrism (1 = low, 4 = high)", 
       y = " ")+
  ylim(0,0.93)

# NSIdeo plot AfD
p3 <- pred_probs_plt_fun(m1_ns_afd, "NSIdeo", "tan4")
p3 <- p3 +
  labs(x = "Neo-Nazi ideology (1 = low, 4 = high)", 
       y = " ")+
  ylim(0,0.93)

# REX plot BSW
p4 <- pred_probs_plt_fun(m1_rex_bsw, "REX", "black")
p4 <- p4 +
  labs(x = "Far-right attitudes (1 = low, 4 = high)", 
       y = "Predicted probability")+
  ylim(0,0.93)

# Ethno plot BSW
p5 <- pred_probs_plt_fun(m1_ethno_bsw, "Ethno", "steelblue1")
p5 <- p5 +
  labs(x = "Ethnocentrism (1 = low, 4 = high)", 
       y = " ")+
  ylim(0,0.93)

# NSIdeo plot BSW
p6 <- pred_probs_plt_fun(m1_ns_bsw, "NSIdeo", "tan4")
p6 <- p6 +
  labs(x = "Neo-Nazi ideology (1 = low, 4 = high)", 
       y = " ")+
  ylim(0,0.93)

## plots on 1 canvas
# AfD plots
p10 <- cowplot::plot_grid(p1,p2,p3,
                          nrow = 1,
                          labels = "(a) AfD vote",
                          label_size = 14,
                          label_fontfamily = "Fira Sans")

# BSW plots
p20 <- cowplot::plot_grid(p4,p5,p6,
                          nrow = 1,
                          labels = "(b) BSW vote",
                          label_size = 14,
                          label_fontfamily = "Fira Sans")
```

```{r pred probs plts full models far-right}
# all plots
cowplot::plot_grid(p10, p20,
                   nrow = 2)
```




# APPENDIX: Robustness Checks and Further Model Specifications

In this section, we compute a series of alternative model specifications to assess the robustness of our findings. These include:

* **Bivariate models**
* **Partial models**, which include only one group of predictors:  
  * either cultural conservatism  
  * or political grievances  
* Models using **only socio-demographic control variables**
* **Full models with alternative operationalizations** of some of our independent variables  
* Models estimated with **unweighted data** 

Regarding the alternative operationalization, we modify or add the following variables:

* `lr` In politics one often talks about ‘left’ and ‘right’. Where would you place yourself: very far-left, fairly far-left, rather left, in the middle, rather right, fairly far-right, very far-right?
* `dev_community` as an alternative measurment of place-based resentment. Originally labelled `SL_VER` in the dataset, respondents were asked to rate the development of their community on a 5-point scale: 'In your view, how has your city/town developed over the past 10 to 15 years?' (This question was only given to respondents who lived in their current hometown since at least 10 years)
* `dissat_parties` anti-party sentiment was operationalized as a dummy based on item `V17`: Parties just want people's votes—they don’t actually care about their views
* `ext_effic`external efficacy was operationalized as a dummy based on item `V139J`: People like me have no say in what the government does.
* `responsive` was operationalized as a dummy based on item `V699`: In general, politicians make an effort to represent the interests of the population. (reversed)


## 1 Partial Regression Models (Cultural Conservatism and Political Grievances)
Partial models calculated on the same cases as the full model (N=975), i.e. all cases containing missing data in the full model were dropped. 

```{r partial models}
# select vars we need
tm <- tm_all %>% 
  select(alter, gender, edu_gr, lr, fin_sit, fair_share, status_anx, anti_immigration, anti_feminism, anti_trans, econ_situation_th, second_class, gdr, swd_gr, pol_distrust, RR, afd, bsw, persgew)

# remove data with missings
tm <- tm %>% 
  drop_na()

# surveydesign object
tm_w <- svydesign(id=~1, weights=~persgew, data = tm)

##### Cultural conservatism #####
m2_afd <- svyglm(afd~anti_immigration+anti_feminism+anti_trans,
                 family = quasibinomial(link = "logit"),
                 design = tm_w)

m2_bsw <- svyglm(bsw~anti_immigration+anti_feminism+anti_trans,
                 family = quasibinomial(link = "logit"),
                 design = tm_w)


##### Political grievances #####
m3_afd <- svyglm(afd~swd_gr+pol_distrust+RR+second_class+gdr,
                 family = quasibinomial(link="logit"),
                 design = tm_w)

m3_bsw <- svyglm(bsw~swd_gr+pol_distrust+RR+second_class+gdr,
                 family = quasibinomial(link="logit"),
                 design = tm_w)
```

```{r modelsummary partial models, warning=F, message=F}
modelsummary(
  list("Cultural grievances (AfD)" = m2_afd,
       "Cultural grievances (BSW)" = m2_bsw,
       "Political grievances (AfD)" = m3_afd,
       "Political grievances (BSW)" = m3_bsw),
  exponentiate = T, # get OR
  stars = T,
  output = "kableExtra",
  statistic = "conf.int",
  gof_omit = "RMSE|R2|Deviance|F|AIC|BIC|Log.Lik",
  title = "Partial logistic regression models predicting AfD and BSW vote choice (Odds Ratios)",
  coef_rename = coef_names
)
```

What do the partial models tell us?
**Cultural grievances** Anti-immigration and-anti-feminism are significantly associated with AfD support. None of the cultural grievances is significant for supporting BSW - though see robustness checks that show a little inconsistency in these findings, and lend some weak indications for a link between BSW support and anti-immigrant views [See section on BSW and anti-immigrant attitudes](#8a-bsw-and-anti-immigrant-attitudes).

**Political grievances** For the AfD, all genuinely political grievances significant; so is place-based resentment, while grievances related to East German identity are not significant. For BSW political grievances seem a somewhat weaker predictor of vote choice. SWD is significantly associated (in expected direction). GDR nostalgia is significant at the 90% level only, but in expected direction as well.


#### Model Fit Statistics

To view model fit statistics, please set `eval = F`and `echo = F`to `TRUE` in the markdown file.  

```{r model fit partial models, eval=F, echo=F}
#### AfD ####
## Cultural grievances 
# AIC & Nagelkerke
model_output(m2_afd)
# LRT approximation / Wald Test
lrt_fun_svyglm("afd", tm_w, m2_afd) 
# McFadden Pseudo R2
quasi_mcfadden("afd", tm_w, m2_afd)

## Political grievances
# AIC & Nagelkerke
model_output(m3_afd)
# LRT approximation / Wald Test
lrt_fun_svyglm("afd", tm_w, m3_afd) 
# McFadden Pseudo R2
quasi_mcfadden("afd", tm_w, m3_afd)


#### BSW ####
## Cultural grievances 
# AIC & Nagelkerke
model_output(m2_bsw)
# LRT approximation / Wald Test
lrt_fun_svyglm("bsw", tm_w, m2_bsw) 
# McFadden Pseudo R2
quasi_mcfadden("bsw", tm_w, m2_bsw)

## Political grievances 
# AIC & Nagelkerke
model_output(m3_bsw)
# LRT approximation / Wald Test
lrt_fun_svyglm("bsw", tm_w, m3_bsw) 
# McFadden Pseudo R2
quasi_mcfadden("bsw", tm_w, m3_bsw)

```


## 1a Partial Regression Models That Let R Handle Missing Data (Cultural Conservatism and Political Grievances)
In this alternative approach for computing the partial regression models for cultural conservatism and political grievances, we rely on R's default handling of missing data within the regression function. Hence, we compute these partial models on a different set of cases as our main models presented in the manuscript. 

```{r partial models no missings removed in advance}
# Select vars we need
tm <- tm_all %>% 
  select(alter, gender, edu_gr, lr, fin_sit, fair_share, status_anx, anti_immigration, anti_feminism, anti_trans, econ_situation_th, second_class, gdr, swd_gr, pol_distrust, RR, afd, bsw, persgew)

# surveydesign object
tm_w <- svydesign(id=~1, weights=~persgew, data = tm)

##### Cultural conservatism #####
m2_afd <- svyglm(afd~anti_immigration+anti_feminism+anti_trans,
                 family = quasibinomial(link = "logit"),
                 design = tm_w)

m2_bsw <- svyglm(bsw~anti_immigration+anti_feminism+anti_trans,
                 family = quasibinomial(link = "logit"),
                 design = tm_w)


##### Political grievances #####
m3_afd <- svyglm(afd~swd_gr+pol_distrust+RR+second_class+gdr,
                 family = quasibinomial(link="logit"),
                 design = tm_w)

m3_bsw <- svyglm(bsw~swd_gr+pol_distrust+RR+second_class+gdr,
                 family = quasibinomial(link="logit"),
                 design = tm_w)
```

```{r modelsummary partial models no missings removed in advance, warning=F, message=F}
modelsummary(
  list("Cultural grievances (AfD)" = m2_afd,
       "Cultural grievances (BSW)" = m2_bsw,
       "Political grievances (AfD)" = m3_afd,
       "Political grievances (BSW)" = m3_bsw),
  exponentiate = T, # get OR
  stars = T,
  output = "kableExtra",
  statistic = "conf.int",
  gof_omit = "RMSE|R2|Deviance|F|AIC|BIC|Log.Lik",
  title = "Partial logistic regression models predicting AfD and BSW vote choice (Odds Ratios)",
  coef_rename = coef_names
)
```

Note that when we let R handle the missing data in the regression function, we observe no changes regarding our main IVs of interest.



## 2 Full svyglm models with left-right self-placement
In this model, we add left-right self-placement as an additional control variable. 

```{r svyglm models with L/R}
# select vars we need
tm <- tm_all %>% 
  select(alter, gender, edu_gr, lr, fin_sit, fair_share, status_anx, anti_immigration, anti_feminism, anti_trans, econ_situation_th, second_class, gdr, swd_gr, pol_distrust, RR, afd, bsw, persgew)

# data w/o NAs (then all models have same cases)
tm <- tm %>% 
  drop_na()

# svydesign
tm_w <- svydesign(id=~1,weights = ~persgew, data=tm)

# MODELS
m_afd <- svyglm(afd~anti_immigration+anti_feminism+anti_trans+second_class+gdr+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+fair_share+status_anx+econ_situation_th+lr,
                family = quasibinomial(link="logit"),
                design = tm_w)

m_bsw <- svyglm(bsw~anti_immigration+anti_feminism+anti_trans+second_class+gdr+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+fair_share+status_anx+econ_situation_th+lr,
                family = quasibinomial(link="logit"),
                design = tm_w)
```

```{r modelsummary full svyglm model including left-right, message=F, warning=F}
modelsummary(
  list("AfD" = m_afd, "BSW" = m_bsw),
  exponentiate = T, # get OR
  stars = T,
  output = "kableExtra",
  statistic = "conf.int",
  gof_omit = "RMSE|R2|Deviance|F|AIC|BIC|Log.Lik",
  title = "Logistic regression models predicting AfD and BSW vote choice including left-right self-placement (Odds Ratios)",
  coef_rename = coef_names
)
```

**Anti-immigrant views lose significance in the AfD model.** Likely this is due to the fact the anti-immigrant attitudes and left-right self-placement are fairly strong correlated:
```{r corr L/R anti-immigrant}
indep_test(tm$anti_immigration, tm$lr,
           weights = tm$persgew,
           method = "pearson") 
```

This makes sense, as individuals with anti-immigrant views tend to place themselves further to the right on the ideological spectrum.

For **BSW, left-right self-placement** shows a **significant negative** association. Since higher values indicate a more right-leaning position, this means that placing oneself more to the left is associated with a greater likelihood of voting for BSW.

#### Model Fit Statistics

To view model fit statistics, please set `eval = F`and `echo = F`to `TRUE` in the markdown file. 

```{r model fit full svyglm models with L/R, eval=F, echo=F}
# AfD
# Nagelkerke & AIC
model_output(m_afd)
# LRT approximation / Wald Test
lrt_fun_svyglm("afd", tm_w, m_afd)
# McFadden Pseudo R2
quasi_mcfadden("afd", tm_w, m_afd)

# BSW
# Nagelkerke & AIC
model_output(m_bsw)
# LRT approximation / Wald Test
lrt_fun_svyglm("bsw", tm_w, m_bsw)
# McFadden Pseudo R2
quasi_mcfadden("bsw", tm_w, m_bsw)
```


## 3 Model *without* GDR nostalgia
In this model, we remove GDR nostalgia as a predictor as this variable has many missing cases (NA > 350), especially among younger respondents.

```{r regressions models without GDR nostalgia}
# select vars we need
tm <- tm_all %>% 
  select(alter, gender, edu_gr, lr, fin_sit, fair_share, status_anx, anti_immigration, anti_feminism, anti_trans, econ_situation_th, second_class, swd_gr, pol_distrust, RR, afd, bsw, persgew)

# data w/o NAs
tm <- tm %>% 
  drop_na()

# Surveydesign object
tm_w <- svydesign(id=~1, weights=~persgew, data = tm)

# MODELS
m_afd <- svyglm(afd~anti_immigration+anti_feminism+anti_trans+second_class+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+fair_share+status_anx+econ_situation_th,
                family = quasibinomial(link="logit"),
                design = tm_w)

m_bsw <- svyglm(bsw~anti_immigration+anti_feminism+anti_trans+second_class+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+fair_share+status_anx+econ_situation_th,
                family = quasibinomial(link="logit"),
                design = tm_w)

```

```{r modelsummary full svyglm models without GDR, warning=F, message=F}
modelsummary(
  list("AfD" = m_afd, "BSW" = m_bsw),
  exponentiate = T, # get OR
  stars = T,
  output = "kableExtra",
  statistic = "conf.int",
  gof_omit = "RMSE|R2|Deviance|F|AIC|BIC|Log.Lik",
  title = "Logistic regression models predicting AfD and BSW vote choice excluding GDR nostalgia (Odds Ratios)",
  coef_rename = coef_names
)
```

Deleting this variable does not affect the AfD model, but it further reduces the explanatory power of the BSW models, as we lose a significant predictor.

#### Model Fit Statistics

To view model fit statistics, please set `eval = F`and `echo = F`to `TRUE` in the markdown file. 

```{r model fit full svyglm models without GDR, eval=F, echo=F}
# AfD
# Nagelkerke & AIC
model_output(m_afd)
# LRT approximation / Wald Test
lrt_fun_svyglm("afd", tm_w, m_afd)
# McFadden Pseudo R2
quasi_mcfadden("afd", tm_w, m_afd)

# BSW
# Nagelkerke & AIC
model_output(m_bsw)
# LRT approximation / Wald Test
lrt_fun_svyglm("bsw", tm_w, m_bsw)
# McFadden Pseudo R2
quasi_mcfadden("bsw", tm_w, m_bsw)
```


## 4 Additional Predictors Political Grievances

We look at anti-party sentiment, external efficacy and perception of responsiveness as additional political grievances. We leave GDR nostalgia out of the model (due to the relatively high no. of NAs)

```{r regression models additional political grievances}
# select vars we need
tm <- tm_all %>% 
  select(alter, gender, edu_gr, lr, fin_sit, fair_share, status_anx, anti_immigration, anti_feminism, anti_trans, econ_situation_th, second_class, swd_gr, pol_distrust, RR, afd, bsw, persgew, dissat_parties, ext_effic, responsive)

# data w/o NAs
tm <- tm %>% 
  drop_na()

# Surveydesign object
tm_w <- svydesign(id=~1, weights=~persgew, data = tm)

# Full models
m_afd <- svyglm(afd~anti_immigration+anti_feminism+anti_trans+second_class+swd_gr+pol_distrust+dissat_parties+ext_effic+responsive+RR+alter+gender+edu_gr+fin_sit+fair_share+status_anx+econ_situation_th,
                family = quasibinomial(link="logit"),
                design = tm_w)

m_bsw <- svyglm(bsw~anti_immigration+anti_feminism+anti_trans+second_class+swd_gr+pol_distrust+dissat_parties+ext_effic+responsive+RR+alter+gender+edu_gr+fin_sit+fair_share+status_anx+econ_situation_th,
                family = quasibinomial(link="logit"),
                design = tm_w)

# partial model all political grievances
m1_afd <- svyglm(afd~second_class+swd_gr+pol_distrust+dissat_parties+ext_effic+responsive+RR,
                family = quasibinomial(link="logit"),
                design = tm_w)

m1_bsw <- svyglm(bsw~second_class+swd_gr+pol_distrust+dissat_parties+ext_effic+responsive+RR,
                family = quasibinomial(link="logit"),
                design = tm_w)

# only anti-party sentiment, external efficacy, and responsiveness
m2_afd <- svyglm(afd~dissat_parties+ext_effic+responsive,
                family = quasibinomial(link="logit"),
                design = tm_w)

m2_bsw <- svyglm(bsw~dissat_parties+ext_effic+responsive,
                family = quasibinomial(link="logit"),
                design = tm_w)

```

```{r modelsummary models additional political grievances, warning=F, message=F}
modelsummary(
  list("AfD" = m_afd, "BSW" = m_bsw,
       "AfD" = m1_afd, "BSW" = m1_bsw,
       "AfD" = m2_afd, "BSW" = m2_bsw),
  exponentiate = T, # get OR
  stars = T,
  output = "kableExtra",
  statistic = "conf.int",
  gof_omit = "RMSE|R2|Deviance|F|AIC|BIC|Log.Lik",
  title = "Logistic regression models predicting AfD and BSW vote choice using additional predictors for political grievances (Odds Ratios)",
  coef_rename = coef_names
)
```

**None of the three alternative operationalizations** of political grievances **reach** conventional levels of **statistical significance in the full models**.

However, in models where these three variables are included on their own, both external efficacy and perceived non-responsiveness of politicians show a significant association with AfD voting — and in the expected direction.

This suggests a possible indirect effect, where feelings of low efficacy and perceived political unresponsiveness contribute to dissatisfaction with democracy, which in turn may help explain support for the AfD.

#### Model Fit Statistics

To view model fit statistics, please set `eval = F`and `echo = F`to `TRUE` in the markdown file. 

```{r model fit models additional political grievances, eval=F, echo=F}
# AfD
## partial models
# Nagelkerke & AIC
model_output(m_afd)
# LRT approximation / Wald Test
lrt_fun_svyglm("afd", tm_w, m_afd)
# McFadden Pseudo R2
quasi_mcfadden("afd", tm_w, m_afd)

## full models
# Nagelkerke & AIC
model_output(m_afd)
# LRT approximation / Wald Test
lrt_fun_svyglm("afd", tm_w, m_afd)
# McFadden Pseudo R2
quasi_mcfadden("afd", tm_w, m_afd)
# Multikollinearity
vif(m_afd)>4

# BSW
## partial models
# Nagelkerke & AIC
model_output(m1_bsw)
# LRT approximation / Wald Test
lrt_fun_svyglm("bsw", tm_w, m1_bsw)
# McFadden Pseudo R2
quasi_mcfadden("bsw", tm_w, m1_bsw)

## Full models
# Nagelkerke & AIC
model_output(m_bsw)
# LRT approximation / Wald Test
lrt_fun_svyglm("bsw", tm_w, m_bsw)
# McFadden Pseudo R2
quasi_mcfadden("bsw", tm_w, m_bsw)
# Multikollinearity
vif(m_bsw)>4
```



## 5 Different Operationalization Place-based Resentment
This time place-based resentment is operationalized as how respondents perceive their community has developed over the last 10-15 years.

```{r regression models place-based resentment alternative}
# select vars we need
tm <- tm_all %>% 
  select(alter, gender, edu_gr, lr, fin_sit, fair_share, status_anx, anti_immigration, anti_feminism, anti_trans, econ_situation_th, second_class, swd_gr, pol_distrust, dev_community, afd, bsw, persgew)

# data w/o NAs
tm <- tm %>% 
  drop_na()

# Surveydesign object
tm_w <- svydesign(id=~1, weights=~persgew, data = tm)

# full models
m_afd <- svyglm(afd~anti_immigration+anti_feminism+anti_trans+second_class+swd_gr+pol_distrust+dev_community+alter+gender+edu_gr+fin_sit+fair_share+status_anx+econ_situation_th,
                family = quasibinomial(link="logit"),
                design = tm_w)

m_bsw <- svyglm(bsw~anti_immigration+anti_feminism+anti_trans+second_class+swd_gr+pol_distrust+dev_community+alter+gender+edu_gr+fin_sit+fair_share+status_anx+econ_situation_th,
                family = quasibinomial(link="logit"),
                design = tm_w)

# partial model
# AfD
m1_afd <- svyglm(afd~second_class+swd_gr+pol_distrust+dev_community,
                family = quasibinomial(link="logit"),
                design = tm_w)

m1_bsw <- svyglm(bsw~second_class+swd_gr+pol_distrust+dev_community,
                family = quasibinomial(link="logit"),
                design = tm_w)
```

```{r modelsummary place-based resentment alternative, warning=F, message=F}
modelsummary(
  list("AfD" = m_afd, "BSW" = m_bsw,
       "AfD" = m1_afd, "BSW" = m1_bsw),
  exponentiate = T, # get OR
  stars = T,
  output = "kableExtra",
  statistic = "conf.int",
  gof_omit = "RMSE|R2|Deviance|F|AIC|BIC|Log.Lik",
  title = "Logistic regression models predicting AfD and BSW vote choice with alternative operationalization of place-based resentment (Odds Ratios)",
  coef_rename = coef_names
)
```

The alternative measure of place-based resentment is not significantly associated with vote choice - neither for BSW nor for the AfD. 

#### Model Fit Statistics

To view model fit statistics, please set `eval = F`and `echo = F`to `TRUE` in the markdown file. 

```{r model fit place-based resentment alternative, eval=F, echo=F}
# AfD
# Nagelkerke & AIC
model_output(m_afd)
# LRT approximation / Wald Test
lrt_fun_svyglm("afd", tm_w, m_afd)
# McFadden Pseudo R2
quasi_mcfadden("afd", tm_w, m_afd)
# Multicollinearity
vif(m_afd)>4

# BSW
# Nagelkerke & AIC
model_output(m_bsw)
# LRT approximation / Wald Test
lrt_fun_svyglm("bsw", tm_w, m_bsw)
# McFadden Pseudo R2
quasi_mcfadden("bsw", tm_w, m_bsw)
# Multicollinearity
vif(m_bsw)>4

```



## 6 Additional Variables Measuring Losers of Modernization Thesis
Next to the characteristics we already use (economic deprivation, status anxiety, education) we now add unemployment and manual occupation to make the set of loser of modernization indicators complete.

```{r regression models additional losers of modernization vars}
# select vars we need
tm <- tm_all %>% 
  select(alter, gender, edu_gr, unemployed, manual_worker, fin_sit, fair_share, status_anx, anti_immigration, anti_feminism, anti_trans, econ_situation_th, second_class, swd_gr, pol_distrust, RR, afd, bsw, persgew)

# data w/o NAs (then all models have same cases)
tm <- tm %>% 
  drop_na()

# Surveydesign object
tm_w <- svydesign(id=~1, weights=~persgew, data = tm)

# full models
m_afd <- svyglm(afd~anti_immigration+anti_feminism+anti_trans+second_class+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share+status_anx+econ_situation_th,
                family = quasibinomial(link="logit"),
                design = tm_w)

m_bsw <- svyglm(bsw~anti_immigration+anti_feminism+anti_trans+second_class+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share+status_anx+econ_situation_th,
                family = quasibinomial(link="logit"),
                design = tm_w)

# partial models (economy / losers of modernization only)
m1_afd <- svyglm(afd~edu_gr+fin_sit+unemployed+manual_worker+fair_share+status_anx+econ_situation_th,
                family = quasibinomial(link="logit"),
                design = tm_w)

m1_bsw <- svyglm(bsw~edu_gr+fin_sit+unemployed+manual_worker+fair_share+status_anx+econ_situation_th,
                family = quasibinomial(link="logit"),
                design = tm_w)

```

```{r modelsummary additional losers of modernization vars, warning=F, message=F}
modelsummary(
  list("AfD" = m_afd, "BSW" = m_bsw,
       "AfD" = m1_afd, "BSW" = m1_bsw),
  exponentiate = T, # get OR
  stars = T,
  output = "kableExtra",
  statistic = "conf.int",
  gof_omit = "RMSE|R2|Deviance|F|AIC|BIC|Log.Lik",
  title = "Logistic regression models predicting AfD and BSW vote choice with additional operationalization of the losers of modernization (Odds Ratios)",
  coef_rename = coef_names
)
```

Adding unemployment and occupation as manual worker to our model does not alter the picture we find for AfD vote choice, both predictors (unemployment, manual worker) are insignificant in the AfD model. In contrast, in the BSW model, unemployment emerges as highly significant and positively associated with voting for BSW. Interestingly, the findings for BSW appear contradictory with regard to the losers of modernization thesis: low education is negatively associated with BSW vote-choice, unemployment positively.

#### Model Fit Statistics
To view model fit statistics, please set `eval = F`and `echo = F`to `TRUE` in the markdown file. 

```{r model fit additional losers of modernization vars, eval=F, echo=F}
# AfD
# Nagelkerke & AIC
model_output(m_afd)
# LRT approximation / Wald Test
lrt_fun_svyglm("afd", tm_w, m_afd)
# McFadden Pseudo R2
quasi_mcfadden("afd", tm_w, m_afd)

# BSW
# Nagelkerke & AIC
model_output(m_bsw)
# LRT approximation / Wald Test
lrt_fun_svyglm("bsw", tm_w, m_bsw)
# McFadden Pseudo R2
quasi_mcfadden("bsw", tm_w, m_bsw)
```



## 7 Unweighted Data (full model)

```{r robustness check unweighted data full}
# select the same vars as in main model
tm <- tm_all %>% 
  select(alter, gender, edu_gr, lr, fin_sit, fair_share, status_anx, anti_immigration, anti_feminism, anti_trans, econ_situation_th, second_class, gdr, swd_gr, pol_distrust, RR, afd, bsw, persgew)

# data w/o NAs
tm <- tm %>% 
  drop_na()

# Regression models
m_afd <- glm(afd~anti_immigration+anti_feminism+anti_trans+second_class+gdr+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+fair_share+status_anx+econ_situation_th,
             family = binomial(link="logit"),
             data=tm)

m_bsw <- glm(bsw~anti_immigration+anti_feminism+anti_trans+second_class+gdr+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+fair_share+status_anx+econ_situation_th,
             family = binomial(link="logit"),
             data=tm)

```

```{r unweighted data model summary}
modelsummary(
  list("AfD" = m_afd, "BSW" = m_bsw),
  exponentiate = T, # get OR
  stars = T,
  output = "kableExtra",
  statistic = "conf.int",
  gof_omit = "RMSE|R2|Deviance|F",
  title = "Table: Full logistic regression models predicting AfD and BSW vote choice, unweighted data (Odds Ratios)",
  coef_rename = coef_names
)
```

Using unweighted data produces some shifts in significance, though the general picture stays the same.
For **AfD**, anti-trans views become significant and *positive*—though only at the 90% level, while our controls age and education lose significance (age drops to 90% level). For **BSW**, political distrust now shows a significant association. Anti-trans views are *negatively* correlated—though also only at the 90% level. Similarly, collective deprivation becomes positively associated, though only at the 90% level. 

To view model fit statistics, please set `eval = F`and `echo = F`to `TRUE` in the markdown file. 

```{r LRT unweighted data full model, eval=F, echo=F}
# AfD
lrt_fun_binomial("afd", tm, m_afd)
#  BSW
lrt_fun_binomial("bsw", tm, m_bsw)
```


### 7a Unweighted data (socio-demographic controls only)
```{r models socio-demographic controls only unweighted}
# select vars we need
tm <- tm_all %>% 
  select(alter, gender, edu_gr, unemployed, manual_worker, fin_sit, fair_share, anti_immigration, anti_feminism, anti_trans, afd, bsw, persgew)

# data w/o NAs
tm <- tm %>% 
  drop_na()

# MODELS
m_afd <- glm(afd~anti_immigration+anti_feminism+anti_trans+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share,
             family = binomial(link="logit"),
             data=tm)

m_bsw <- glm(bsw~anti_immigration+anti_feminism+anti_trans+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share,
             family = binomial(link="logit"),
             data=tm)
```

```{r modelsummary socio-demographic controls only unweighted}
modelsummary(
  list("AfD" = m_afd, "BSW" = m_bsw),
  exponentiate = T, # get OR
  stars = T,
  output = "kableExtra",
  statistic = "conf.int",
  gof_omit = "RMSE|R2|Deviance|F",
  title = "Table: Logistic regression models with socio-demographic controls predicting AfD and BSW vote choice, unweighted data (Odds Ratios)",
  coef_rename = coef_names
)
```

In the AfD model, anti-trans views become significant and positive; so does anti-feminism. The most noteworthy shift regarding **BSW** is that **anti-immigrant views become positive, and significantly associated**. Anti-feminism emerges as a significant predictor - though only at the 90% level - and anti-feminism is negatively associated with voting for BSW. 

We explore the relationship between BSW vote and anti-immigrant views in even greater detail in [section 10a on BSW and anti-immigrant attitudes](#10a-bsw-and-anti-immigrant-attitudes).

To view model fit statistics, please set `eval = F`and `echo = F`to `TRUE` in the markdown file. 

```{r LRT models socio-demographic controls only unweighted, eval=F, echo=F}
lrt_fun_binomial("afd", tm, m_afd) 
lrt_fun_binomial("bsw", tm, m_bsw)  
```


## 8 Far-right Attitudes: Bivariate and Socio-demographic Controls models
In this section we look at further models predicting the link between far-right attitudes and vote choice. These models are:

* bivariate models
* models using only socio-demographic controls

### 8a Bivariate regression models

```{r bivariate models far-right}
# Select vars we need
tm_rex <- tm_all %>% 
  select(REX, Ethno, NSIdeo, persgew, afd, bsw)

# drop NA to have same cases in all models
tm_rex <- tm_rex %>% 
  drop_na()

# surveydesign object
tm_rex_w <- svydesign(id=~1, weights=~persgew, data = tm_rex)

# MODELS
m_rex_afd <- svyglm(afd~REX,
                    family = quasibinomial(link = "logit"),
                    design = tm_rex_w)

m_ethno_afd <- svyglm(afd~Ethno,
                    family = quasibinomial(link = "logit"),
                    design = tm_rex_w)

m_ns_afd <- svyglm(afd~NSIdeo,
                      family = quasibinomial(link = "logit"),
                      design = tm_rex_w)

m_rex_bsw <- svyglm(bsw~REX,
                    family = quasibinomial(link = "logit"),
                    design = tm_rex_w)

m_ethno_bsw <- svyglm(bsw~Ethno,
                    family = quasibinomial(link = "logit"),
                    design = tm_rex_w)

m_ns_bsw <- svyglm(bsw~NSIdeo,
                      family = quasibinomial(link = "logit"),
                      design = tm_rex_w)
```

```{r modelsummaries far-right bivariate, warning=F, message=F}
modelsummary(
  list("Far-right (AfD)" = m_rex_afd,
       "Ethnocentrism (AfD)" = m_ethno_afd,
       "Neo-Nazi ideology (AfD)" = m_ns_afd,
       "Far-right (BSW)" = m_rex_bsw, 
       "Ethnocentrism (BSW)" = m_ethno_bsw, 
       "Neo-Nazi ideology (BSW)" = m_ns_bsw
       ),
  exponentiate = T, # get OR
  stars = T,
  output = "kableExtra",
  statistic = "conf.int",
  gof_omit = "RMSE|R2|Deviance|F|AIC|BIC|Log.Lik",
  title = "Table: Bivariate Logistic regression models predicting AfD and BSW vote choice with far-right attitudes (Odds Ratios)",
  coef_rename = coef_names
)
```


What do the overall bivariate results tell us?

All three dimensions of far-right attitudes are **significantly associated** with **AfD voting**, but **none** are significant for **BSW** voters.  
This confirms previous findings linking the AfD support to far-right attitudes, while the BSW results stand in contrast to earlier research finding initial indications for a link between BSW support and views from the broader spectrum of far-right attitudes.

However, in the **unweighted data** ([see robustness checks](#9a-bivariate-models-far-right-attitudes-unweighted)), both the **full far-right attitude scale** and its **ethnocentrism** subscale are significantly associated with BSW voting in the bivariate models. Neo-Nazi ideology, on the other hand, is not. 


#### Model fit

To view model fit statistics, please set `eval = F`and `echo = F`to `TRUE` in the markdown file. 

```{r model fit bivariate modesl far-right, eval=F, echo=F}
#### AfD ####
## Far-right
# Nagelkerke & AIC
model_output(m_rex_afd)
# LRT approximation / Wald Test
lrt_fun_svyglm("afd", tm_rex_w, m_rex_afd)
# McFadden Pseudo R2
quasi_mcfadden("afd", tm_rex_w, m_rex_afd)

## Ethnocentrism
# Nagelkerke & AIC
model_output(m_ethno_afd) 
# LRT approximation / Wald Test
lrt_fun_svyglm("afd", tm_rex_w, m_ethno_afd)
# McFadden Pseudo R2
quasi_mcfadden("afd", tm_rex_w, m_ethno_afd)

## neo-Nazi Ideology
# Nagelkerke & AIC
model_output(m_ns_afd) 
# LRT approximation / Wald Test
lrt_fun_svyglm("afd", tm_rex_w, m_ns_afd)
# McFadden Pseudo R2
quasi_mcfadden("afd", tm_rex_w, m_ns_afd)


#### BSW ####
## Far-right
# Nagelkerke & AIC
model_output(m_rex_bsw) 
# LRT approximation / Wald Test
lrt_fun_svyglm("bsw", tm_rex_w, m_rex_bsw)
# McFadden Pseudo R2
quasi_mcfadden("bsw", tm_rex_w, m_rex_bsw)

## Ethnocentrism
# Nagelkerke & AIC
model_output(m_ethno_bsw) 
# LRT approximation / Wald Test
lrt_fun_svyglm("bsw", tm_rex_w, m_ethno_bsw)
# McFadden Pseudo R2
quasi_mcfadden("bsw", tm_rex_w, m_ethno_bsw)

## neo-Nazi Ideology
# Nagelkerke & AIC
model_output(m_ns_bsw) 
# LRT approximation / Wald Test
lrt_fun_svyglm("bsw", tm_rex_w, m_ns_bsw)
# McFadden Pseudo R2
quasi_mcfadden("bsw", tm_rex_w, m_ns_bsw)

```


#### Predicted probabilitiess

```{r predicted probabilities far-right bivariate, warning=F, message=F, echo=F}
# REX plot AfD
p1 <- pred_probs_plt_fun(m_rex_afd, "REX", "black")
p1 <- p1 +
  labs(x = "Far-right attitudes (1 = low, 4 = high)", 
       y = "Predicted probability")+
  ylim(0,0.93)

# Ethno plot AfD
p2 <- pred_probs_plt_fun(m_ethno_afd, "Ethno", "steelblue1")
p2 <- p2 +
  labs(x = "Ethnocentrism (1 = low, 4 = high)", 
       y = " ")+
  ylim(0,0.93)

# NSIdeo plot AfD
p3 <- pred_probs_plt_fun(m_ns_afd, "NSIdeo", "tan4")
p3 <- p3 +
  labs(x = "Neo-Nazi ideology (1 = low, 4 = high)", 
       y = " ")+
  ylim(0,0.93)

# REX plot BSW
p4 <- pred_probs_plt_fun(m_rex_bsw, "REX", "black")
p4 <- p4 +
  labs(x = "Far-right attitudes (1 = low, 4 = high)", 
       y = "Predicted probability")+
  ylim(0,0.93)

# Ethno plot BSW
p5 <- pred_probs_plt_fun(m_ethno_bsw, "Ethno", "steelblue1")
p5 <- p5 +
  labs(x = "Ethnocentrism (1 = low, 4 = high)", 
       y = " ")+
  ylim(0,0.93)

# NSIdeo plot BSW
p6 <- pred_probs_plt_fun(m_ns_bsw, "NSIdeo", "tan4")
p6 <- p6 +
  labs(x = "Neo-Nazi ideology (1 = low, 4 = high)", 
       y = " ")+
  ylim(0,0.93)

## plots on 1 canvas
# AfD plots
p10 <- cowplot::plot_grid(p1,p2,p3,
                   nrow = 1,
                   labels = "(a) AfD vote",
                   label_size = 14,
                   label_fontfamily = "Fira Sans")

# BSW plots
p20 <- cowplot::plot_grid(p4,p5,p6,
                   nrow = 1,
                   labels = "(b) BSW vote",
                   label_size = 14,
                   label_fontfamily = "Fira Sans")

```

```{r pred probs plts bivariate}
# all plots
cowplot::plot_grid(p10, p20,
                   nrow = 2)
```


### 8b Regression Models Far-right Attitudes with Socio-demographic Controls
```{r regressions far-right attitudes socio-demographic controls only}
# select vars we need
tm_rex <- tm_all %>% 
  select(REX, Ethno, NSIdeo, persgew, afd, bsw, alter, gender, edu_gr, fin_sit, fair_share, unemployed, manual_worker)

# drop NA to have same cases in all models
tm_rex <- tm_rex %>% 
  drop_na()

# surveydesign object
tm_rex_w <- svydesign(id=~1, weights=~persgew, data = tm_rex)

# MODELS
m1_rex_afd <- svyglm(afd~REX+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share,
                    family = quasibinomial(link = "logit"),
                    design = tm_rex_w)

m1_rex_bsw <- svyglm(bsw~REX+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share,
                    family = quasibinomial(link = "logit"),
                    design = tm_rex_w)

m1_ethno_afd <- svyglm(afd~Ethno+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share,
                    family = quasibinomial(link = "logit"),
                    design = tm_rex_w)

m1_ethno_bsw <- svyglm(bsw~Ethno+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share,
                    family = quasibinomial(link = "logit"),
                    design = tm_rex_w)

m1_ns_afd <- svyglm(afd~NSIdeo+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share,
                    family = quasibinomial(link = "logit"),
                    design = tm_rex_w)

m1_ns_bsw <- svyglm(bsw~NSIdeo+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share,
                    family = quasibinomial(link = "logit"),
                    design = tm_rex_w)
```

```{r modelsummary far-right socio-demographcs only, warning=F, message=F}
modelsummary(
  list("Far-right (AfD)" = m1_rex_afd,
       "Ethnocentrism (AfD)" = m1_ethno_afd,
       "Neo-Nazi ideology (AfD)" = m1_ns_afd,
       "Far-right (BSW)" = m1_rex_bsw, 
       "Ethnocentrism (BSW)" = m1_ethno_bsw, 
       "Neo-Nazi ideology (BSW)" = m1_ns_bsw
       ),
  exponentiate = T, # get OR
  stars = T,
  output = "kableExtra",
  statistic = "conf.int",
  gof_omit = "RMSE|R2|Deviance|F|AIC|BIC|Log.Lik",
  title = "Table: Logistic regression models with socio-demographic controls predicting AfD and BSW vote choice with far-right attitudes (Odds Ratios)",
  coef_rename = coef_names
)
```


#### Model Fit Statistics

To view model fit statistics, please set `eval = F`and `echo = F`to `TRUE` in the markdown file. 

```{r model fit far-right socio-demographcs only, eval=F, echo=F}
#### AfD ####
## Far-right attitudes 
# Nagelkerke & AIC
model_output(m1_rex_afd)
# LRT approximation / Wald Test
lrt_fun_svyglm("afd", tm_rex_w, m1_rex_afd)
# McFadden Pseudo R2
quasi_mcfadden("afd", tm_rex_w, m1_rex_afd)

## Ethnocentrism 
# Nagelkerke & AIC
model_output(m1_ethno_afd) 
# LRT approximation / Wald Test
lrt_fun_svyglm("afd", tm_rex_w, m1_ethno_afd)
# McFadden Pseudo R2
quasi_mcfadden("afd", tm_rex_w, m1_ethno_afd)

## neo-Nazi ideology 
# Nagelkerke & AIC
model_output(m1_ns_afd) 
# LRT approximation / Wald Test
lrt_fun_svyglm("afd", tm_rex_w, m1_ns_afd)
# McFadden Pseudo R2
quasi_mcfadden("afd", tm_rex_w, m1_ns_afd)

#### BSW ####
## Far-right attitudes 
# Nagelkerke & AIC
model_output(m1_rex_bsw) 
# LRT approximation / Wald Test
lrt_fun_svyglm("bsw", tm_rex_w, m1_rex_bsw)
# McFadden Pseudo R2
quasi_mcfadden("bsw", tm_rex_w, m1_rex_bsw)

## Ethnocentrism 
# Nagelkerke & AIC
model_output(m1_ethno_bsw) 
# LRT approximation / Wald Test
lrt_fun_svyglm("bsw", tm_rex_w, m1_ethno_bsw)
# McFadden Pseudo R2
quasi_mcfadden("bsw", tm_rex_w, m1_ethno_bsw)

## neo-Nazi ideology
# Nagelkerke & AIC
model_output(m1_ns_bsw) 
# LRT approximation / Wald Test
lrt_fun_svyglm("bsw", tm_rex_w, m1_ns_bsw)
# McFadden Pseudo R2
quasi_mcfadden("bsw", tm_rex_w, m1_ns_bsw)
```


## 9 Models Far-right Attitudes using Unweighted Data
### 9a Bivariate Models Far-right Attitudes *unweighted*

To test the robustness of our findings regarding the association (or non-association) between far-right attitudes and AfD/BSW vote choice, we now compute further robustness checks using unweighted data. These additional models include:

* simple bivariate models,

* models with socio-demographic controls,

* full models

```{r bivariate regressions far-right unweighted}
# Select vars we need 
tm_rex <- tm_all %>% 
  select(REX, REXgr, Ethno, Ethnogr, NSIdeo, NSIdeogr, persgew, recall_ltw_named, afd, bsw)

# drop NA 
tm_rex <- tm_rex %>% 
  drop_na()

# surveydesign object
tm_rex_w <- svydesign(id=~1, weights=~persgew, data = tm_rex)

# MODELS
m_rex_afd2 <- glm(afd~REX,
                  family = binomial(link = "logit"),
                  data = tm_rex)

m_rex_bsw2 <- glm(bsw~REX,
                  family = binomial(link = "logit"),
                  data = tm_rex)

m_ethno_afd2 <- glm(afd~Ethno,
                    family = binomial(link = "logit"),
                    data = tm_rex)

m_ethno_bsw2 <- glm(bsw~Ethno,
                    family = binomial(link = "logit"),
                    data = tm_rex)

m_ns_afd2 <- glm(afd~NSIdeo,
                 family = binomial(link = "logit"),
                 data = tm_rex)

m_ns_bsw2 <- glm(bsw~NSIdeo,
                 family = binomial(link = "logit"),
                 data = tm_rex)
```

```{r modelsummary bivariate regressions far-right unweighted}
modelsummary(
  list("Far-right (AfD)" = m_rex_afd2,
       "Ethnocentrism (AfD)" = m_ethno_afd2,
       "Neo-Nazi ideology (AfD)" = m_ns_afd2,
       "Far-right (BSW)" = m_rex_bsw2, 
       "Ethnocentrism (BSW)" = m_ethno_bsw2, 
       "Neo-Nazi ideology (BSW)" = m_ns_bsw2
       ),
  exponentiate = T, # get OR
  stars = T,
  output = "kableExtra",
  statistic = "conf.int",
  gof_omit = "RMSE|R2|Deviance|F",
  title = "Table: Bivariate logistic regression models predicting AfD and BSW vote choice with far-right attitudes, unweighted data (Odds Ratios)",
  coef_rename = coef_names
)
```

Computing the far-right attitudes models with unweighted data is where we find the most striking differences for BSW support in comparison to the models above computed using the weighted data. 

Both the full far-right attitude scale and its ethnocentrism subscale are significantly associated with BSW voting in bivariate models. Yet, in comparison between AfD and BSW, it’s worth noting that the OR for ethnocentrism is much smaller for BSW (1.4 vs. 7.2), this shows how much more strongly far-right attitudes are tied to AfD support. Yet, these findings from the unweighted data aren’t entirely surprising. As shown in the [bivariate analysis](#bivariate-analysis) crosstables, BSW voters display a **higher share of far-right/ethnocentric views** compared to voters of the left-wing parties Greens, SPD, and the Left — though their share is lower than that of AfD or CDU voters.


### 9b Models with Socio-demographic Controls Far-right Attitudes *unweighted*

```{r regression models far-right socio-demographic controls unweighted}
# select vars we need
tm_rex <- tm_all %>% 
  select(REX, REXgr, Ethno, Ethnogr, NSIdeo, NSIdeogr, persgew, recall_ltw_named, afd, bsw, alter, gender, edu_gr, fin_sit, fair_share, unemployed, manual_worker)

# drop NA to have same cases in all models
tm_rex <- tm_rex %>% 
  drop_na()

# surveydesign object
tm_rex_w <- svydesign(id=~1, weights=~persgew, data = tm_rex)

# MODELS
m1_rex_afd2 <- glm(afd~REX+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share,
                   family = binomial(link = "logit"),
                   data = tm_rex)

m1_ethno_afd2 <- glm(afd~Ethno+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share,
                     family = binomial(link = "logit"),
                     data = tm_rex)

m1_ns_afd2 <- glm(afd~NSIdeo+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share,
                  family = binomial(link = "logit"),
                  data = tm_rex)

m1_rex_bsw2 <- glm(bsw~REX+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share,
                   family = binomial(link = "logit"),
                   data = tm_rex)

m1_ethno_bsw2 <- glm(bsw~Ethno+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share,
                     family = binomial(link = "logit"),
                     data = tm_rex)

m1_ns_bsw2 <- glm(bsw~NSIdeo+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share,
                  family = binomial(link = "logit"),
                  data = tm_rex)
```

```{r modelsummary regressions far-right socio-demographic controls unweighted}
modelsummary(
  list("Far-right (AfD)" = m1_rex_afd2,
       "Ethnocentrism (AfD)" = m1_ethno_afd2,
       "Neo-Nazi ideology (AfD)" = m1_ns_afd2,
       "Far-right (BSW)" = m1_rex_bsw2, 
       "Ethnocentrism (BSW)" = m1_ethno_bsw2, 
       "Neo-Nazi ideology (BSW)" = m1_ns_bsw2
       ),
  exponentiate = T, # get OR
  stars = T,
  output = "kableExtra",
  statistic = "conf.int",
  gof_omit = "RMSE|R2|Deviance|F",
  title = "Table: Logistic regression models with socio-demographic controls predicting AfD and BSW vote choice with far-right attitudes, unweighted data (Odds Ratios)",
  coef_rename = coef_names
)
```

As expected, all three far-right attitudes scales are significantly associated with AfD support in the unweighted data as well. 

In the unweighted data with socio-demographic controls, ethnocentrism remains significantly linked to BSW support (similar to the bivariate model), while the far-right attitudes full scale and the neo-Nazi ideology subscale are not signifcantly associated.

To view model fit statistics, please set `eval = F`and `echo = F`to `TRUE` in the markdown file. 

```{r LRT unweighted data far-right socio-demographic controls, eval=F, echo=F}
# AfD
lrt_fun_binomial("afd", tm_rex, m1_rex_afd2)
lrt_fun_binomial("afd", tm_rex, m1_ethno_afd2)
lrt_fun_binomial("afd", tm_rex, m1_ns_afd2)

#  BSW
lrt_fun_binomial("bsw", tm_rex, m1_rex_bsw2)
lrt_fun_binomial("bsw", tm_rex, m1_ethno_bsw2)
lrt_fun_binomial("bsw", tm_rex, m1_ns_bsw2)
```


### 9c Full Models Far-right Attitudes *unweighted*
```{r full regression models far-right unweighted}
# select vars we need
tm_rex <- tm_all %>% 
  select(REX, REXgr, Ethno, Ethnogr, NSIdeo, NSIdeogr, alter, gender, edu_gr, unemployed, manual_worker, fin_sit, fair_share, status_anx, anti_immigration, anti_feminism, anti_trans, econ_situation_th, second_class, swd_gr, pol_distrust, RR, afd, bsw, persgew)

# drop NA to have same cases in all models
tm_rex <- tm_rex %>% 
  drop_na()

# surveydesign object
tm_rex_w <- svydesign(id=~1, weights=~persgew, data = tm_rex)

# MODELS
m1_rex_afd <- glm(afd~REX+anti_feminism+anti_trans+second_class+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share+status_anx+econ_situation_th,
                     family = binomial(link = "logit"),
                     data = tm_rex)

m1_rex_bsw <- glm(bsw~REX+anti_feminism+anti_trans+second_class+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share+status_anx+econ_situation_th,
                     family = binomial(link = "logit"),
                     data = tm_rex)

m1_ethno_afd <- glm(afd~Ethno+anti_feminism+anti_trans+second_class+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share+status_anx+econ_situation_th,
                       family = binomial(link = "logit"),
                       data = tm_rex)

m1_ethno_bsw <- glm(bsw~Ethno+anti_feminism+anti_trans+second_class+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share+status_anx+econ_situation_th,
                       family = binomial(link = "logit"),
                       data = tm_rex)

m1_ns_afd <- glm(afd~NSIdeo+anti_feminism+anti_trans+second_class+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share+status_anx+econ_situation_th,
                    family = binomial(link = "logit"),
                    data = tm_rex)

m1_ns_bsw <- glm(bsw~NSIdeo+anti_feminism+anti_trans+second_class+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share+status_anx+econ_situation_th,
                    family = binomial(link = "logit"),
                    data = tm_rex)

```

```{r modelsummary full regression models far-right unweighted}
modelsummary(
  list("Far-right (AfD)" = m1_rex_afd,
       "Ethnocentrism (AfD)" = m1_ethno_afd,
       "Neo-Nazi ideology (AfD)" = m1_ns_afd,
       "Far-right (BSW)" = m1_rex_bsw, 
       "Ethnocentrism (BSW)" = m1_ethno_bsw, 
       "Neo-Nazi ideology (BSW)" = m1_ns_bsw
       ),
  exponentiate = T, # get OR
  stars = T,
  output = "kableExtra",
  statistic = "conf.int",
  gof_omit = "RMSE|R2|Deviance|F",
  title = "Table: Full logistic regression models predicting AfD and BSW vote choice with far-right attitudes, unweighted data (Odds Ratios)",
  coef_rename = coef_names
)
```

Computing the full models using unweighted data, the results for **BSW are again consistent with what we found in the main models** presented in the manuscript. None of the three far-right attitudes scales is associated with BSW support in the full models using unweighted data.

In contrast, for the **AfD, neo-Nazi ideology** displays a **significant** (rather than insignificant) association.

To view model fit statistics, please set `eval = F`and `echo = F`to `TRUE` in the markdown file. 

```{r LRT full regression models far-right unweighted, eval=F, echo=F}
# AfD
lrt_fun_binomial("afd", tm_rex, m1_rex_afd)
lrt_fun_binomial("afd", tm_rex, m1_ethno_afd)
lrt_fun_binomial("afd", tm_rex, m1_ns_afd)

#  BSW
lrt_fun_binomial("bsw", tm_rex, m1_rex_bsw)
lrt_fun_binomial("bsw", tm_rex, m1_ethno_bsw)
lrt_fun_binomial("bsw", tm_rex, m1_ns_bsw)
```



## 10 Additional Robustness Checks BSW and Cultural Conservatism

In these additional robustness checks, we take a closer look at the consistency of the non-significant association between voting for BSW and cultural conservatism.
We estimate 11 additional models for each measure of cultural grievances: anti-immigrant attitudes, anti-feminism, and anti-trans views.

These models include:

* simple bivariate models,

* models with socio-demographic controls,

* full models

For each type, we run versions using both weighted and unweighted data.
Additionally, we test two approaches to handling missing data:

* One approach uses a reduced sample where all cases with missing values were removed in advance (N = 975); like in the main model

* The other approach relies on R's default handling of missing data within the regression function


### 10a BSW and Anti-immigrant Attitudes
```{r set up data robustness checks BSW cult conserv}
# we do this with variables from main models 
tm <- tm_all %>% 
  select(alter, gender, edu_gr, lr, fin_sit, fair_share, status_anx, anti_immigration, anti_feminism, anti_trans, econ_situation_th, second_class, gdr, swd_gr, pol_distrust, RR, afd, bsw, persgew)

# data w/o NAs 
tm <- tm %>% 
  drop_na()

# Surveydesign object
tm_w <- svydesign(id=~1, weights=~persgew, data = tm) # svydesign sample with all missings removed in advance, N=975
tm_all_w <- svydesign(id=~1, weights=~persgew, data = tm_all) # svydesign all cases
```

```{r BSW anti immigrant models}
## limited sample (N=975), all missings removed in advance
### bivariate
#### weighted svyglm
m1 <- svyglm(bsw~anti_immigration,
            family = quasibinomial(link="logit"),
            design = tm_w)

#### unweighted
m2 <- glm(bsw~anti_immigration,
         family = binomial(link="logit"),
         data = tm)

### socio-demographic controls
#### weighted svyglm
m3 <- svyglm(bsw~anti_immigration+alter+gender+edu_gr+fin_sit+fair_share,
            family = quasibinomial(link="logit"),
            design = tm_w)

#### unweighted
m4 <- glm(bsw~anti_immigration+alter+gender+edu_gr+fin_sit+fair_share,
         family = binomial(link="logit"),
         data = tm)

### full model
#### *weighted svyglm -> main model!

#### unweighted
m5 <- glm(bsw~anti_immigration+anti_feminism+anti_trans+second_class+gdr+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+fair_share+status_anx+econ_situation_th,
         family = binomial(link="logit"),
         data = tm)


## full sample, missings get removed during regression
### bivariate
#### weighted svyglm
m6 <- svyglm(bsw~anti_immigration,
            family = quasibinomial(link="logit"),
            design = tm_all_w)

#### unweighted
m7 <- glm(bsw~anti_immigration,
         family = binomial(link="logit"),
         data = tm_all)

### socio-demographic controls
#### weighted svyglm
m8<- svyglm(bsw~anti_immigration+alter+gender+edu_gr+fin_sit+fair_share,
            family = quasibinomial(link="logit"),
            design = tm_all_w)

#### unweighted
m9 <- glm(bsw~anti_immigration+alter+gender+edu_gr+fin_sit+fair_share,
         family = binomial(link="logit"),
         data = tm_all)

### full model
#### weighted svyglm 
m10 <- svyglm(bsw~anti_immigration+anti_feminism+anti_trans+second_class+gdr+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+fair_share+status_anx+econ_situation_th,
                family = quasibinomial(link="logit"),
                design = tm_all_w)

#### unweighted
m11 <- glm(bsw~anti_immigration+anti_feminism+anti_trans+second_class+gdr+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+fair_share+status_anx+econ_situation_th,
         family = binomial(link="logit"),
         data = tm_all)

```

```{r modelsummaries robustness BSW anti-immigrant, warning=F, message=F}
modelsummary(
  list("weighted"=m1,
       "unweighted"=m2,
       "weighted"=m3,
       "unweighted"=m4,
       "unweighted"=m5,
       "weighted"=m6,
       "unweighted"=m7,
       "weighted"=m8,
       "unweighted"=m9,
       "weighted"=m10,
       "unweighted"=m11),
  exponentiate = T, # get OR
  stars = T,
  output = "kableExtra",
  statistic = "conf.int",
  gof_omit = "RMSE|R2|Deviance|F|AIC|BIC|Log.Lik",
  title = "Table: Logistic regression models predicting BSW vote choice with anti-immigrant attitudes (Odds Ratios)",
  coef_rename = coef_names
)
```

**Anti-immigrant views** are **positive** and significantly associated with BSW voting in 3 models, plus 1 additional model at the 90% confidence level. Hence, in total this predictor is significant in 4/12 models (around 33%). This suggests that the non-significant pattern found in the main model is somewhat less consistent. However, in none of the 4 specifications of the full model (including the main model) is this predictor significant.

Yet, the **effect size (odds ratio) is consistently much smaller than what we observe for the AfD** (the OR never exceeds 1.5). The effect also becomes weaker when socio-demographic controls are added, and the statistical significance disappears completely once all variables are included. This could suggest an indirect effect of anti-immigrant views via political dissatisfaction (i.e., anti-immigrant views -> dissatisfaction with democracy/politics -> BSW vote).


### 10b BSW and Anti-feminism

```{r BSW anti feminism models}
## bivariate
#### weighted svyglm
m1 <- svyglm(bsw~anti_feminism,
            family = quasibinomial(link="logit"),
            design = tm_w)

#### unweighted
m2 <- glm(bsw~anti_feminism,
         family = binomial(link="logit"),
         data = tm)

### socio-demographic controls
#### weighted svyglm
m3 <- svyglm(bsw~anti_feminism+alter+gender+edu_gr+fin_sit+fair_share,
            family = quasibinomial(link="logit"),
            design = tm_w)

#### unweighted
m4 <- glm(bsw~anti_feminism+alter+gender+edu_gr+fin_sit+fair_share,
         family = binomial(link="logit"),
         data = tm)

### full model
#### weighted svyglm -> main model!

#### unweighted
m5 <- glm(bsw~anti_immigration+anti_feminism+anti_trans+second_class+gdr+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+fair_share+status_anx+econ_situation_th,
         family = binomial(link="logit"),
         data = tm)


## full sample, missings get removed during regression

### bivariate
#### weighted svyglm
m6 <- svyglm(bsw~anti_feminism,
            family = quasibinomial(link="logit"),
            design = tm_all_w)

#### unweighted
m7 <- glm(bsw~anti_feminism,
         family = binomial(link="logit"),
         data = tm_all)

### socio-demographic controls
#### weighted svyglm
m8 <- svyglm(bsw~anti_feminism+alter+gender+edu_gr+fin_sit+fair_share,
            family = quasibinomial(link="logit"),
            design = tm_all_w)

#### unweighted
m9 <- glm(bsw~anti_feminism+alter+gender+edu_gr+fin_sit+fair_share,
         family = binomial(link="logit"),
         data = tm_all)

### full model
#### *weighted svyglm 
m10 <- svyglm(bsw~anti_immigration+anti_feminism+anti_trans+second_class+gdr+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+fair_share+status_anx+econ_situation_th,
            family = quasibinomial(link="logit"),
            design = tm_all_w)

#### unweighted
m11 <- glm(bsw~anti_immigration+anti_feminism+anti_trans+second_class+gdr+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+fair_share+status_anx+econ_situation_th,
         family = binomial(link="logit"),
         data = tm_all)

```

```{r modelsummaries robustness BSW anti-feminism, warning=F, message=F}
modelsummary(
  list("weighted"=m1,
       "unweighted"=m2,
       "weighted"=m3,
       "unweighted"=m4,
       "unweighted"=m5,
       "weighted"=m6,
       "unweighted"=m7,
       "weighted"=m8,
       "unweighted"=m9,
       "weighted"=m10,
       "unweighted"=m11),
  exponentiate = T, # get OR
  stars = T,
  output = "kableExtra",
  statistic = "conf.int",
  gof_omit = "RMSE|R2|Deviance|F|AIC|BIC|Log.Lik",
  title = "Table: Logistic regression models predicting BSW vote choice with anti-feminist attitudes (Odds Ratios)",
  coef_rename = coef_names
)
```

### 10c BSW and Anti-trans Attitudes

```{r BSW anti-trans models}
### bivariate
#### weighted svyglm
m1 <- svyglm(bsw~anti_trans,
            family = quasibinomial(link="logit"),
            design = tm_w)

#### unweighted
m2 <- glm(bsw~anti_trans,
         family = binomial(link="logit"),
         data = tm)

### socio-demographic controls
#### weighted svyglm
m3 <- svyglm(bsw~anti_trans+alter+gender+edu_gr+fin_sit+fair_share,
            family = quasibinomial(link="logit"),
            design = tm_w)

#### unweighted
m4 <- glm(bsw~anti_trans+alter+gender+edu_gr+fin_sit+fair_share,
         family = binomial(link="logit"),
         data = tm)

### full model
#### weighted svyglm -> main model!

#### unweighted
m5 <- glm(bsw~anti_immigration+anti_feminism+anti_trans+second_class+gdr+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+fair_share+status_anx+econ_situation_th,
         family = binomial(link="logit"),
         data = tm)


## full sample, missings get removed during regression

### bivariate
#### weighted svyglm
m6 <- svyglm(bsw~anti_trans,
            family = quasibinomial(link="logit"),
            design = tm_all_w)

#### unweighted
m7 <- glm(bsw~anti_trans,
         family = binomial(link="logit"),
         data = tm_all)

### socio-demographic controls
#### weighted svyglm
m8 <- svyglm(bsw~anti_trans+alter+gender+edu_gr+fin_sit+fair_share,
            family = quasibinomial(link="logit"),
            design = tm_all_w)

#### unweighted
m9 <- glm(bsw~anti_trans+alter+gender+edu_gr+fin_sit+fair_share,
         family = binomial(link="logit"),
         data = tm_all)

### full model
#### weighted svyglm 
m10 <- svyglm(bsw~anti_immigration+anti_feminism+anti_trans+second_class+gdr+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+fair_share+status_anx+econ_situation_th,
            family = quasibinomial(link="logit"),
            design = tm_all_w)

#### unweighted
m11 <- glm(bsw~anti_immigration+anti_feminism+anti_trans+second_class+gdr+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+fair_share+status_anx+econ_situation_th,
         family = binomial(link="logit"),
         data = tm_all)
```

```{r modelsummaries robustness BSW anti-trans, warning=F, message=F}
modelsummary(
  list("weighted"=m1,
       "unweighted"=m2,
       "weighted"=m3,
       "unweighted"=m4,
       "unweighted"=m5,
       "weighted"=m6,
       "unweighted"=m7,
       "weighted"=m8,
       "unweighted"=m9,
       "weighted"=m10,
       "unweighted"=m11),
  exponentiate = T, # get OR
  stars = T,
  output = "kableExtra",
  statistic = "conf.int",
  gof_omit = "RMSE|R2|Deviance|F|AIC|BIC|Log.Lik",
  title = "Table: Logistic regression models predicting BSW vote choice with anti-trans attitudes (Odds Ratios)",
  coef_rename = coef_names
)
```

What do these further robustness checks tell us?

**Anti-trans** and **anti-feminist** views are **never** significantly and positively associated with voting BSW. For anti-trans views, there are a few instances that show a **negative** association at the 90% level (2/12 models).


## 11 All models on the same set of cases
Let's do one last robustness check, where we run all models on the exact same cases. That means we also include the far-right attitudes variables in the dataframe we use for the cultural conservatism/political grievances models and remove the missings prior to the analysis. This leaves us with N=963 cases.

We will look at:

* all full models
* partial modles with only cultural conservatism/political grievances
* bivariate model for far-right attitudes

```{r all modles on the same data}
# select vars we need
tm <- tm_all %>% 
  select(alter, gender, edu_gr, fin_sit, fair_share, status_anx, unemployed, manual_worker, anti_immigration, anti_feminism, anti_trans, econ_situation_th, second_class, gdr, swd_gr, pol_distrust, RR, afd, bsw, REX, Ethno, NSIdeo, persgew)

# remove data with missings
tm <- tm %>% 
  drop_na()
dim(tm)

# surveydesign object
tm_w <- svydesign(id=~1, weights=~persgew, data = tm)

# MODELS
##### Cultural conservatism #####
m1_afd <- svyglm(afd~anti_immigration+anti_feminism+anti_trans,
                 family = quasibinomial(link = "logit"),
                 design = tm_w)

m1_bsw <- svyglm(bsw~anti_immigration+anti_feminism+anti_trans,
                 family = quasibinomial(link = "logit"),
                 design = tm_w)


##### Political grievances #####
m2_afd <- svyglm(afd~swd_gr+pol_distrust+RR+second_class+gdr,
                 family = quasibinomial(link="logit"),
                 design = tm_w)

m2_bsw <- svyglm(bsw~swd_gr+pol_distrust+RR+second_class+gdr,
                 family = quasibinomial(link="logit"),
                 design = tm_w)


#### Full model cultural/political grievances ####
m3_afd <- svyglm(afd~anti_immigration+anti_feminism+anti_trans+second_class+gdr+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+fair_share+unemployed+manual_worker+status_anx+econ_situation_th,
                family = quasibinomial(link="logit"),
                design = tm_w)

m3_bsw <- svyglm(bsw~anti_immigration+anti_feminism+anti_trans+second_class+gdr+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+fair_share+unemployed+manual_worker++status_anx+econ_situation_th,
                family = quasibinomial(link="logit"),
                design = tm_w)

#### Far-right bivariate ####
m_rex_afd <- svyglm(afd~REX,
                    family = quasibinomial(link = "logit"),
                    design = tm_w)

m_ethno_afd <- svyglm(afd~Ethno,
                    family = quasibinomial(link = "logit"),
                    design = tm_w)

m_ns_afd <- svyglm(afd~NSIdeo,
                      family = quasibinomial(link = "logit"),
                      design = tm_w)

m_rex_bsw <- svyglm(bsw~REX,
                    family = quasibinomial(link = "logit"),
                    design = tm_w)

m_ethno_bsw <- svyglm(bsw~Ethno,
                    family = quasibinomial(link = "logit"),
                    design = tm_w)

m_ns_bsw <- svyglm(bsw~NSIdeo,
                      family = quasibinomial(link = "logit"),
                      design = tm_w)

#### Far-right full ####
# MODELS
m1_rex_afd <- svyglm(afd~REX+anti_feminism+anti_trans+second_class+gdr+swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share+status_anx+econ_situation_th,
                     family = quasibinomial(link = "logit"),
                     design = tm_w)

m1_rex_bsw <- svyglm(bsw~REX+anti_feminism+anti_trans+second_class+gdr++swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share+status_anx+econ_situation_th,
                     family = quasibinomial(link = "logit"),
                     design = tm_w)

m1_ethno_afd <- svyglm(afd~Ethno+anti_feminism+anti_trans+second_class+gdr++swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share+status_anx+econ_situation_th,
                       family = quasibinomial(link = "logit"),
                       design = tm_w)

m1_ethno_bsw <- svyglm(bsw~Ethno+anti_feminism+anti_trans+second_class+gdr++swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share+status_anx+econ_situation_th,
                       family = quasibinomial(link = "logit"),
                       design = tm_w)

m1_ns_afd <- svyglm(afd~NSIdeo+anti_feminism+anti_trans+second_class+gdr++swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share+status_anx+econ_situation_th,
                    family = quasibinomial(link = "logit"),
                    design = tm_w)

m1_ns_bsw <- svyglm(bsw~NSIdeo+anti_feminism+anti_trans+second_class+gdr++swd_gr+pol_distrust+RR+alter+gender+edu_gr+fin_sit+unemployed+manual_worker+fair_share+status_anx+econ_situation_th,
                    family = quasibinomial(link = "logit"),
                    design = tm_w)

```
 
```{r modelsummary all modles on the same data, warning=F, message=F}
# Model summaries cultural/political grievances
modelsummary(
  list("AfD" = m1_afd, "BSW" = m1_bsw,
       "AfD" = m2_afd, "BSW" = m2_bsw,
       "AfD" = m3_afd, "BSW" = m3_bsw),
  exponentiate = T, # get OR
  stars = T,
  output = "kableExtra",
  statistic = "conf.int",
  gof_omit = "RMSE|R2|Deviance|F|AIC|BIC|Log.Lik",
  title = "Logistic regression models predicting AfD and BSW vote choice with regard to cultural conservatism and political grievances (Odds Ratios)",
  coef_rename = coef_names
)

# Model summaries far-right
## Bivariate
modelsummary(
  list("Far-right (AfD)" = m_rex_afd,
       "Ethnocentrism (AfD)" = m_ethno_afd,
       "Neo-Nazi ideology (AfD)" = m_ns_afd,
       "Far-right (BSW)" = m_rex_bsw, 
       "Ethnocentrism (BSW)" = m_ethno_bsw, 
       "Neo-Nazi ideology (BSW)" = m_ns_bsw
       ),
  exponentiate = T, # get OR
  stars = T,
  output = "kableExtra",
  statistic = "conf.int",
  gof_omit = "RMSE|R2|Deviance|F|AIC|BIC|Log.Lik",
  title = "Table: Bivariate Logistic regression models predicting AfD and BSW vote choice with far-right attitudes (Odds Ratios)",
  coef_rename = coef_names
)

## Full model
modelsummary(
  list("Far-right (AfD)" = m1_rex_afd,
       "Ethnocentrism (AfD)" = m1_ethno_afd,
       "Neo-Nazi ideology (AfD)" = m1_ns_afd,
       "Far-right (BSW)" = m1_rex_bsw, 
       "Ethnocentrism (BSW)" = m1_ethno_bsw, 
       "Neo-Nazi ideology (BSW)" = m1_ns_bsw
       ),
  exponentiate = T, # get OR
  stars = T,
  output = "kableExtra",
  statistic = "conf.int",
  gof_omit = "RMSE|R2|Deviance|F|AIC|BIC|Log.Lik",
  title = "Table: Full Logistic regression models predicting AfD and BSW vote choice with far-right attitudes (Odds Ratios)",
  coef_rename = coef_names
)
```

Overall, the results are consistent with the earlier findings from the main models presented in the manuscript.

The only notable difference: the association between **BSW vote choice and far-right attitudes**, as well as the **ethnocentrism subscale**, is **negative and significant** (though only at the 90% level in the case of the full far-right attitudes scale).  

This may, however, be due to the inclusion of **GDR nostalgia** as a further control in the far-right attitudes models.


# Summary statistics all variables
```{r summary statistics all vars}

# survey design object
tm_all_w <- svydesign(id=~1, weights=~persgew, data = tm_all)

##### functions #####
# function: summary stats for metric vars
my_descriptives <- function(var_name, design_name) {
  list(
    mean = round(svymean(~var_name, design_name, na.rm=T),3),
    quantiles = svyquantile(~var_name, design_name, c(0.25, 0.5, 0.75), na.rm=T),
    sd = round(sqrt(svyvar(~var_name, design_name , na.rm=T)),3)
  )
}

# input in my_descriptives: tm_all_w$variables$var_name

# function: summary stats for categorical/dummy
descriptives_table <- function(var_name, design_name) {
  var_name_new <- as.formula(paste0("~", var_name))
  t <- svytable(var_name_new , design_name)
  list(absolute = round(t,0),
       percent = round(prop.table(t)*100,1)
  )
}

# input in descriptives_table: "var_name"


##### NAs #####
# check NA for all vars
## select var we need
tm <- tm_all %>% 
  select(alter, gender, edu_gr, lr, fin_sit, fair_share, status_anx, anti_immigration, anti_feminism, anti_trans, econ_situation_th, second_class, gdr, swd_gr, pol_distrust, RR, afd, bsw, unemployed, manual_worker)

## NA check (unweighted)
colSums(is.na(tm))


##### Summary satistics #####

## Metric
# Anti-immigrant attitudes
my_descriptives(tm_all_w$variables$anti_immigration, tm_all_w) # pass name as this, otherwise it will not find the varname in the design

# Far-right attitudes 
my_descriptives(tm_all_w$variables$REX, tm_all_w)

# Ethnocentrism subscale
my_descriptives(tm_all_w$variables$Ethno, tm_all_w)

# Neo-Nazi ideology subscale
my_descriptives(tm_all_w$variables$NSIdeo, tm_all_w)

# Political distrust
my_descriptives(tm_all_w$variables$pol_distrust, tm_all_w)

# Place-based resentment
my_descriptives(tm_all_w$variables$RR, tm_all_w)

# L/R
my_descriptives(tm_all_w$variables$lr, tm_all_w)

# Age
my_descriptives(tm_all_w$variables$alter, tm_all_w)


## Categorical
# Anti-feminism
descriptives_table("anti_feminism", tm_all_w)
# Anti-trans
descriptives_table("anti_trans", tm_all_w)
# Second class
descriptives_table("second_class", tm_all_w)
# GDR nostalgia
descriptives_table("gdr", tm_all_w)
# Dissatisfaction with democracy
descriptives_table("swd_gr", tm_all_w)
# Individual financial situation
descriptives_table("fin_sit", tm_all_w)
# Econ. deprivation
descriptives_table("fair_share", tm_all_w)
# Status anxiety
descriptives_table("status_anx", tm_all_w)
# Economic situation Thuringia 
descriptives_table("econ_situation_th", tm_all_w)
# Gender
descriptives_table("gender", tm_all_w)
# Education
descriptives_table("edu_gr", tm_all_w)
# Occupational status
descriptives_table("unemployed", tm_all_w)
descriptives_table("manual_worker", tm_all_w)

```


# Scale consistency

```{r scale consistency IVs, include=T}

tm <- tm_all

# check scale consistency anti-immigration attitudes
## alpha
psych::alpha(tm[,c("V12A", "V12B", "V12MU", "V469", "V356C_rev")]) # 0.88 
## corrplot
df_immi <- tm %>% 
  select(V12A, V12B, V12MU, V469, V356C_rev)
ggcorr(df_immi,
       method = c("pairwise", "spearman"),
       label=T,
       label_round = 2)

# check distribution
summary(tm$anti_immigration)
hist(tm$anti_immigration, 
     freq = F,
     col="dodgerblue2")


# scale consistency far-right attitudes
## alpha
psych::alpha(tm[,c("V12A", "V12B", "V12C", "V12E")]) # Ethno: 0.83 = good
psych::alpha(tm[,c("V12D", "V12F", "V12G", "V12H", "V12I", "V12J")]) # NSIdeo: 0.73 = acceptable
psych::alpha(tm[,c("V12A", "V12B", "V12C", "V12D", "V12E", "V12F", "V12G", "V12H", "V12I", "V12J")]) # Far-rights full-scale: 0.85 = good

## corrplot
df_rex <- tm %>% 
  select(V12A, V12B, V12C, V12D, V12E, V12F, V12G, V12H, V12I, V12J)
ggcorr(df_rex,
       method=c("pairwise", "spearman"),
       label=T,
       label_round = 2)


# check scale consistency and NAs political grievances
## Place-based resentment
# alpha
psych::alpha(tm[,c("RR1B", "RR2B", "RR4B")]) # 0.67 -> just so acceptable
# corrplot
df_RR <- tm %>% 
  select(RR1B, RR2B, RR4B)
ggcorr(df_RR,
       method=c("pairwise", "spearman"),
       label = T,
       label_round = 2)
# NAs
colSums(is.na(tm[,c("RR1B", "RR2B", "RR4B")]))

## Political trust
psych::alpha(tm[,c("V09A", "V09B", "V09BT")]) # good: 0.85


```


# Session Info
* R version 4.5.0 (2025-04-11)
* Platform: aarch64-apple-darwin20
* Running under: macOS Sequoia 15.6.1

```{r}
sessionInfo()
```

